﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

// Только для внутреннего использования.
// Проверяет действительность сертификата криптографии.
// Только для работы через средства платформы (МенеджерКриптографии).
//
// Параметры:
//   МенеджерКриптографии - Неопределено - получить менеджер криптографии автоматически.
//                        - МенеджерКриптографии - использовать указанный менеджер криптографии.
//
//   Сертификат           - СертификатКриптографии - сертификат.
//                        - ДвоичныеДанные - двоичные данные сертификата.
//                        - Строка - адрес временного хранилища, содержащего двоичные данные сертификата.
//
//   ОписаниеОшибки       - Null - вызвать исключение при ошибке проверки.
//                        - Строка - содержит описание ошибки, если произошла ошибка.
//
//   НаДату               - Дата - проверить сертификат на указанную дату.
//                          Если параметр не указан или указана пустая дата,
//                          тогда проверять на текущую дату сеанса.
//   ДополнительныеПараметры -см. ДополнительныеПараметрыПроверкиСертификата
//
// Возвращаемое значение:
//  Булево - Истина, если проверка выполнена успешно,
//           Ложь, если не удалось получить менеджер криптографии (когда не указан).
//
Функция ПроверитьСертификат(МенеджерКриптографии, Сертификат, ОписаниеОшибки = Null, НаДату = Неопределено, ДополнительныеПараметры = Неопределено) Экспорт
	
	ВызыватьИсключение = ОписаниеОшибки = Null;
	МенеджерКриптографииДляПроверки = МенеджерКриптографии;
	
	СертификатДляПроверки = Сертификат;
	
	Если ТипЗнч(Сертификат) = Тип("Строка") Тогда
		СертификатДляПроверки = ПолучитьИзВременногоХранилища(Сертификат);
	КонецЕсли;
	
	Если ТипЗнч(СертификатДляПроверки) = Тип("ДвоичныеДанные") Тогда
		ДанныеСертификата = СертификатДляПроверки;
		СертификатДляПроверки = Новый СертификатКриптографии(СертификатДляПроверки);
	Иначе
		ДанныеСертификата = СертификатДляПроверки.Выгрузить();
	КонецЕсли;
	
	Если МенеджерКриптографииДляПроверки = Неопределено Тогда
		ИспользоватьЭлектроннуюПодписьВМоделиСервиса =
			ИспользоватьЭлектроннуюПодписьВМоделиСервиса();
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ПоказатьОшибку = ВызыватьИсключение И Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса;
		Если ТипЗнч(ДанныеСертификата) = Тип("ДвоичныеДанные") Тогда
			ПараметрыСоздания.АлгоритмПодписи =
				ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(ДанныеСертификата);
		КонецЕсли;
		
		МенеджерКриптографииДляПроверки = МенеджерКриптографии(
			"ПроверкаСертификата", ПараметрыСоздания);
		
		Если МенеджерКриптографииДляПроверки = Неопределено Тогда
			ОписаниеОшибки = ПараметрыСоздания.ОписаниеОшибки;
			
			Если Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса Тогда
				Возврат Ложь;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	РежимыПроверкиСертификата = ЭлектроннаяПодписьСлужебныйКлиентСервер.РежимыПроверкиСертификата(
		ЗначениеЗаполнено(НаДату));
	
	Если МенеджерКриптографииДляПроверки = Неопределено
	 Или МенеджерКриптографииДляПроверки = "СервисКриптографии" Тогда
		
		МодульСервисКриптографии = ОбщегоНазначения.ОбщийМодуль("СервисКриптографии");
		ПараметрыПроверки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыПроверкиСертификатаВСервисе(
			ЭлектроннаяПодпись.ОбщиеНастройки(), РежимыПроверкиСертификата);
		Попытка
			Если ПараметрыПроверки <> Неопределено Тогда
				// АПК:287-выкл - №640 - допустимо вызывать несуществующую процедуру БТС,
				// так как проверяется версия БТС 2.0.3, начиная с которой процедура существует.
				Результат = МодульСервисКриптографии.ПроверитьСертификатСПараметрами(ДанныеСертификата, ПараметрыПроверки);
				// АПК:287-вкл
			Иначе
				Результат = МодульСервисКриптографии.ПроверитьСертификат(ДанныеСертификата);
			КонецЕсли;
		Исключение
			ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
			Если ВызыватьИсключение Тогда
				ВызватьИсключение;
			КонецЕсли;
			Возврат Ложь;
		КонецПопытки;
		Если Не Результат Тогда
			ОписаниеОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиСервисаСертификатНедействителен();
			Если ВызыватьИсключение Тогда
				ВызватьИсключение ОписаниеОшибки;
			КонецЕсли;
			Возврат Ложь;
		КонецЕсли;
	Иначе
		РезультатПроверкиНаКорректность = ПроверитьСертификатНаКорректность(МенеджерКриптографииДляПроверки, СертификатДляПроверки, 
			РежимыПроверкиСертификата, ОписаниеОшибки, ВызыватьИсключение);
		Если Не РезультатПроверкиНаКорректность Тогда
			Если ВызыватьИсключение Тогда
				ВызватьИсключение ОписаниеОшибки;
			КонецЕсли;
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	ОшибкаПросрочки = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатПросрочен(СертификатДляПроверки,
		НаДату, ДобавкаВремени());
	
	Если ЗначениеЗаполнено(ОшибкаПросрочки) Тогда
		ОписаниеОшибки = ОшибкаПросрочки;
		Если ВызыватьИсключение Тогда
			ВызватьИсключение ОписаниеОшибки;
		КонецЕсли;
		Возврат Ложь;
	КонецЕсли;
	
	Если ДополнительныеПараметры = Неопределено Тогда
		ДополнительныеПараметры = ДополнительныеПараметрыПроверкиСертификата();
	КонецЕсли;
	
	СвойстваСертификата = Неопределено;
	Если ДополнительныеПараметры.ДляПроверкиПодписи Тогда
		
		СвойстваСертификата = ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваСертификата(
			СертификатДляПроверки, ДобавкаВремени(), ДанныеСертификата);
			
		ОшибкаПросрочки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗакрытыйКлючПросрочен(СвойстваСертификата, НаДату);

		Если ЗначениеЗаполнено(ОшибкаПросрочки) Тогда
			ОписаниеОшибки = ОшибкаПросрочки;
			Если ВызыватьИсключение Тогда
				ВызватьИсключение ОписаниеОшибки;
			КонецЕсли;
			Возврат Ложь;
		КонецЕсли;
	КонецЕсли;
	
	Если ДополнительныеПараметры.ВыполнятьПроверкуУдостоверяющегоЦентра Тогда
		
		Результат = РезультатПроверкиУдостоверяющегоЦентраСертификата(СертификатДляПроверки, НаДату,
			ДополнительныеПараметры.ДляПроверкиПодписи, СвойстваСертификата);
		
		Если Не Результат.Действует Или ДополнительныеПараметры.Свойство("Сертификат") И ЗначениеЗаполнено(Результат.Предупреждение.ТекстОшибки)
				И Не ДополнительныеПараметры.ДляПроверкиПодписи Тогда
			
			ПользовательскиеНастройкиСертификата = ЭлектроннаяПодписьСлужебныйВызовСервера.ПользовательскиеНастройкиСертификата(
					СертификатДляПроверки.Отпечаток);

			Если Не Результат.Действует Тогда
				
				Если ПользовательскиеНастройкиСертификата.ПодписаниеРазрешено <> Истина Тогда
					ОписаниеОшибки = Результат.Предупреждение.ТекстОшибки;
					ДополнительныеПараметры.Предупреждение = Результат.Предупреждение;
					Если ВызыватьИсключение Тогда
						ВызватьИсключение ОписаниеОшибки;
					КонецЕсли;
					Возврат Ложь;
				КонецЕсли;
				
			КонецЕсли;

			Если ДополнительныеПараметры.Свойство("Сертификат") И ЗначениеЗаполнено(Результат.Предупреждение.ТекстОшибки)
				И Не ДополнительныеПараметры.ДляПроверкиПодписи Тогда
				
				Если ПользовательскиеНастройкиСертификата.Оповещен
					Или ПользовательскиеНастройкиСертификата.СсылкаНаСертификат = Неопределено Тогда
					ДополнительныеПараметры.Предупреждение = Неопределено;
				Иначе
					ДополнительныеПараметры.Предупреждение = Результат.Предупреждение;
					ДополнительныеПараметры.Сертификат = ПользовательскиеНастройкиСертификата.СсылкаНаСертификат;
				КонецЕсли;
			КонецЕсли;
			
		КонецЕсли;
	КонецЕсли;
	
	Если ВызыватьИсключение Тогда
		ОписаниеОшибки = Null;
	Иначе
		ОписаниеОшибки = "";
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

Функция ДополнительныеПараметрыПроверкиСертификата() Экспорт
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ВыполнятьПроверкуУдостоверяющегоЦентра", Истина);
	ДополнительныеПараметры.Вставить("ДляПроверкиПодписи", Ложь);
	ДополнительныеПараметры.Вставить("Предупреждение");
	
	Возврат ДополнительныеПараметры;
	
КонецФункции

// Только для внутреннего использования.
Функция Зашифровать(Данные, Сертификат, МенеджерКриптографии) Экспорт

	ОписаниеОшибки = "";

	Попытка
		ДвоичныеДанныеРезультата = МенеджерКриптографии.Зашифровать(Данные, Сертификат);
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеЗашифрованныеДанные(ДвоичныеДанныеРезультата, ОписаниеОшибки);
	Исключение
		ОписаниеОшибки = ИнформацияОбОшибке();
	КонецПопытки;
	
	Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда
		ВызватьИсключение ОписаниеОшибки;
	КонецЕсли;
	
	Возврат ДвоичныеДанныеРезультата;

КонецФункции

// Только для внутреннего использования.
Функция ЗашифроватьВСервисеОблачнойПодписи(Данные, Сертификат, УчетнаяЗапись = Неопределено) Экспорт
	
	Если ИспользоватьСервисОблачнойПодписи() Тогда

		МодульСервисКриптографииDSS = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSS");
		
		Если УчетнаяЗапись = Неопределено Тогда
			УчетнаяЗаписьDSSРезультат = МодульСервисКриптографииDSS.НастройкиПодключенияСлужебнойУчетнойЗаписи();
			Если Не УчетнаяЗаписьDSSРезультат.Выполнено Тогда
				ВызватьИсключение  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Сервис DSS:
					|%1'"), УчетнаяЗаписьDSSРезультат.Ошибка);
			КонецЕсли;
			УчетнаяЗаписьDSS = УчетнаяЗаписьDSSРезультат.Результат;
		Иначе
			УчетнаяЗаписьDSS = УчетнаяЗапись;
		КонецЕсли;
		
		ОписаниеОшибки = "";
		Попытка
			Результат = МодульСервисКриптографииDSS.Зашифровать(
						УчетнаяЗаписьDSS, Данные, Сертификат, "CMS");
			Если Результат.Выполнено Тогда
				ДвоичныеДанныеРезультата = Результат.Результат;
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеЗашифрованныеДанные(ДвоичныеДанныеРезультата, ОписаниеОшибки);
			Иначе
				ОписаниеОшибки = Результат.Ошибка;
			КонецЕсли;
		Исключение
			ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		КонецПопытки;

	Иначе
		ОписаниеОшибки = НСтр("ru = 'Не настроен сервис DSS.'");
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда
		ВызватьИсключение  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Сервис DSS:
					|%1'"), ОписаниеОшибки);
	КонецЕсли;
		
	Возврат ДвоичныеДанныеРезультата;
	
КонецФункции

// Только для внутреннего использования.
Функция ЗашифроватьВстроеннымКриптопровайдером(Данные, Сертификат) Экспорт

	Если ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
		МодульСервисКриптографии = ОбщегоНазначения.ОбщийМодуль("СервисКриптографии");
		ОписаниеОшибки = "";
		Попытка
			ДвоичныеДанныеРезультата = МодульСервисКриптографии.Зашифровать(Данные, Сертификат);
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеЗашифрованныеДанные(ДвоичныеДанныеРезультата, ОписаниеОшибки);
		Исключение
			ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		КонецПопытки;
	Иначе
		ОписаниеОшибки = НСтр("ru = 'Не настроен встроенный криптопровайдер.'");
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда
		ВызватьИсключение  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Встроенный криптопровайдер:
					|%1'"), ОписаниеОшибки);
	КонецЕсли;
		
	Возврат ДвоичныеДанныеРезультата;
	
КонецФункции

// Добавляет сертификаты к переданному объекту.
Процедура ДобавитьСертификатыШифрования(ОбъектСсылка, МассивОтпечатков) Экспорт
	УстановитьПривилегированныйРежим(Истина);
	
	ПорядковыйНомер = 1;
	Для Каждого ОтпечатокСтруктура Из МассивОтпечатков Цикл
		МенеджерЗаписи = РегистрыСведений.СертификатыШифрования.СоздатьМенеджерЗаписи();
		МенеджерЗаписи.ЗашифрованныйОбъект = ОбъектСсылка;
		МенеджерЗаписи.Отпечаток = ОтпечатокСтруктура.Отпечаток;
		МенеджерЗаписи.Представление = ОтпечатокСтруктура.Представление;
		МенеджерЗаписи.Сертификат = Новый ХранилищеЗначения(ОтпечатокСтруктура.Сертификат);
		МенеджерЗаписи.ПорядковыйНомер = ПорядковыйНомер;
		ПорядковыйНомер = ПорядковыйНомер + 1;
		МенеджерЗаписи.Записать();
	КонецЦикла;

КонецПроцедуры

// Очищает записи о сертификатах шифрования после расшифровка объекта.
Процедура ОчиститьСертификатыШифрования(ОбъектСсылка) Экспорт
	УстановитьПривилегированныйРежим(Истина);
	
	НаборЗаписей = РегистрыСведений.СертификатыШифрования.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.ЗашифрованныйОбъект.Установить(ОбъектСсылка);
	НаборЗаписей.Записать(Истина);

КонецПроцедуры

// Только для внутреннего использования.
// 
// Параметры:
//  Форма - ФормаКлиентскогоПриложения
//  ИмяСпискаПодписей - Строка
//
Процедура ОформитьСписокПодписей(Форма, ИмяСпискаПодписей) Экспорт
	
	Элемент = Форма.УсловноеОформление.Элементы.Добавить();
	
	ПолеЭлемента = Элемент.Поля.Элементы.Добавить();
	ПолеЭлемента.Поле = Новый ПолеКомпоновкиДанных(ИмяСпискаПодписей);
	
	ОтборЭлемента = Элемент.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ОтборЭлемента.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяСпискаПодписей + ".ПодписьВерна");
	ОтборЭлемента.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
	ОтборЭлемента.ПравоеЗначение = Ложь;
	
	Элемент.Оформление.УстановитьЗначениеПараметра("ЦветТекста", ЦветаСтиля.ЦветОсобогоТекста);
	
КонецПроцедуры

// Определяет доступность электронной подписи для объекта (по его типу)
// 
// Параметры:
//  ТипОбъекта - Тип
// 
// Возвращаемое значение:
//  Булево - доступна электронная подпись
//
Функция ДоступнаЭлектроннаяПодпись(ТипОбъекта) Экспорт
	
	Возврат ЭлектроннаяПодписьСлужебныйПовтИсп.ТипыВладельцев().Получить(ТипОбъекта) <> Неопределено;
	
КонецФункции

// Возвращает адрес сертификата во временном хранилище и его расширение.
//
// Параметры:
//  СведенияОЭлектроннойПодписи - Структура - строка с подписями из массива полученного методом ЭлектроннаяПодпись.УстановленныеПодписи.
//  УникальныйИдентификатор     - УникальныйИдентификатор - идентификатор формы.
// 
// Возвращаемое значение:
//  Структура:
//   * РасширениеСертификата - Строка - расширение файла сертификата.
//   * АдресСертификата      - Строка - адрес во временном хранилище, по которому был помещен сертификат.
//
Функция ДанныеПоСертификату(СведенияОЭлектроннойПодписи, УникальныйИдентификатор) Экспорт
	
	Результат = Новый Структура("РасширениеСертификата, АдресСертификата");
	ДанныеСертификата = СведенияОЭлектроннойПодписи.Сертификат.Получить();
		
		Если ТипЗнч(ДанныеСертификата) = Тип("Строка") Тогда
			Результат.РасширениеСертификата = "txt";
			Результат.АдресСертификата = ПоместитьВоВременноеХранилище(
				ДвоичныеДанныеСтроки(ДанныеСертификата), УникальныйИдентификатор);
		Иначе
			Результат.РасширениеСертификата = "cer";
			Результат.АдресСертификата = ПоместитьВоВременноеХранилище(
				ДанныеСертификата, УникальныйИдентификатор);
		КонецЕсли;
		
	Возврат Результат;
	
КонецФункции

// Возвращает признак возможности интерактивного использования электронных подписей и шифрования 
// для текущего пользователя.
//
// Возвращаемое значение:
//  Булево - если Истина, то интерактивное использование электронных подписей и шифрование возможно.
//
Функция ИнтерактивноеИспользованиеЭлектронныхПодписейИШифрования() Экспорт
	
	Возврат ПравоДоступа("Просмотр", Метаданные.Справочники.СертификатыКлючейЭлектроннойПодписиИШифрования);
	
КонецФункции

// Из переданных имен файлов выделяются имена файлов данных и имена файлов их подписей.
// Сопоставление происходит по правилам формирования имени подписи и расширения файла подписи (p7s).
// Например:
//  Имя файла данных:  "example.txt"
//  имя файла подписи: "example-Ivanov Petr.p7s"
//  имя файла подписи: "example-Ivanov Petr (1).p7s".
//
// Параметры:
//  ИменаФайлов - Массив - имена файлов типа Строка.
//
// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ     - Строка - имя файла.
//   * Значение - Массив - имена файлов подписей типа Строка.
// 
Функция ИменаФайловПодписейИменФайловДанных(ИменаФайлов) Экспорт
	
	РасширениеДляФайловПодписи = ЭлектроннаяПодпись.ПерсональныеНастройки().РасширениеДляФайловПодписи;
	
	Результат = Новый Соответствие;
	
	// Разделяем файлы по расширению.
	ИменаФайловДанных = Новый Массив;
	ИменаФайловПодписей = Новый Массив;
	
	Для Каждого ИмяФайла Из ИменаФайлов Цикл
		Если СтрЗаканчиваетсяНа(ИмяФайла, РасширениеДляФайловПодписи) Тогда
			ИменаФайловПодписей.Добавить(ИмяФайла);
		Иначе
			ИменаФайловДанных.Добавить(ИмяФайла);
		КонецЕсли;
	КонецЦикла;
	
	// Отсортируем имена файлов данных по убыванию числа символов в строке.
	
	Для ИндексА = 1 По ИменаФайловДанных.Количество() Цикл
		ИндексМАКС = ИндексА; // Считаем что текущий файл имеет самое большое число символов.
		Для ИндексБ = ИндексА+1 По ИменаФайловДанных.Количество() Цикл
			Если СтрДлина(ИменаФайловДанных[ИндексМАКС-1]) > СтрДлина(ИменаФайловДанных[ИндексБ-1]) Тогда
				ИндексМАКС = ИндексБ;
			КонецЕсли;
		КонецЦикла;
		своп = ИменаФайловДанных[ИндексА-1];
		ИменаФайловДанных[ИндексА-1] = ИменаФайловДанных[ИндексМАКС-1];
		ИменаФайловДанных[ИндексМАКС-1] = своп;
	КонецЦикла;
	
	// Поиск соответствий имен файлов.
	Для Каждого ИмяФайлаДанных Из ИменаФайловДанных Цикл
		Результат.Вставить(ИмяФайлаДанных, НайтиИменаФайловПодписей(ИмяФайлаДанных, ИменаФайловПодписей));
	КонецЦикла;
	
	// Оставшиеся файлы подписей не распознаны как подписи относящиеся к какому то файлу.
	Для Каждого ИмяФайлаПодписи Из ИменаФайловПодписей Цикл
		Результат.Вставить(ИмяФайлаПодписи, Новый Массив);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Только для внутреннего использования.
// 
// Параметры:
//  ДанныеСертификатов - Массив из ДвоичныеДанные
// 
// Возвращаемое значение:
//  Массив из ДвоичныеДанные - сертификаты по порядку до корневого
//
Функция СертификатыПоПорядкуДоКорневого(ДанныеСертификатов) Экспорт
	
	ПоПорядку = Новый Массив;
	ОписаниеСертификатов = Новый Соответствие;
	СертификатыПоСубъектам = Новый Соответствие;
	
	Для Каждого ДанныеСертификата Из ДанныеСертификатов Цикл
		Сертификат = Новый СертификатКриптографии(ДанныеСертификата);
		ПоПорядку.Добавить(ДанныеСертификата);
		ОписаниеСертификатов.Вставить(Сертификат, ДанныеСертификата);
		СертификатыПоСубъектам.Вставить(
			ЭлектроннаяПодписьСлужебныйКлиентСервер.КлючИздателя(Сертификат.Субъект),
			ДанныеСертификата);
	КонецЦикла;
	
	Для Счетчик = 1 По ПоПорядку.Количество() Цикл
		ЕстьИзменения = Ложь;
		ЭлектроннаяПодписьСлужебныйКлиентСервер.УпорядочитьСертификаты(
			ПоПорядку, ОписаниеСертификатов, СертификатыПоСубъектам, ЕстьИзменения); 
		Если Не ЕстьИзменения Тогда
			Прервать;
		КонецЕсли;
	КонецЦикла;
		
	Возврат ПоПорядку;

КонецФункции

// Только для внутреннего использования.
// 
// Параметры:
//  СертификатКриптографии
//  НаДату - Неопределено, Дата
//  ЭтоПроверкаПодписи - Булево - это проверка подписи, предупреждение (не ошибка) не будет показано.
// 
// Возвращаемое значение:
//   см. ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатПроверкиУдостоверяющегоЦентраПоУмолчанию
//
Функция РезультатПроверкиУдостоверяющегоЦентраСертификата(СертификатКриптографии, НаДату = Неопределено, ЭтоПроверкаПодписи = Ложь, СвойстваСертификата = Неопределено) Экспорт
	
	Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатПроверкиУдостоверяющегоЦентраПоУмолчанию();
	
	// Локализация
	Если Метаданные.ОбщиеМодули.Найти("ЭлектроннаяПодписьСлужебныйЛокализация") = Неопределено 
		Или ЭлектроннаяПодписьСлужебныйПовтИсп.АккредитованныеУдостоверяющиеЦентры() = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	МодульЭлектроннаяПодписьКлиентСерверЛокализация = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьКлиентСерверЛокализация");
	ДанныеДляПроверкиУдостоверяющегоЦентра = МодульЭлектроннаяПодписьКлиентСерверЛокализация.ДанныеДляПроверкиУдостоверяющегоЦентра(
		СертификатКриптографии);
		
	Если ДанныеДляПроверкиУдостоверяющегоЦентра.ЗначенияПоиска = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;
	
	ДанныеУдостоверяющегоЦентра = ЭлектроннаяПодписьСлужебныйПовтИсп.ДанныеУдостоверяющегоЦентра(
		ДанныеДляПроверкиУдостоверяющегоЦентра.ЗначенияПоиска);
		
	Если ДанныеУдостоверяющегоЦентра = Неопределено Тогда
		Возврат Результат;
	КонецЕсли;

	КонтекстПроверки = МодульЭлектроннаяПодписьКлиентСерверЛокализация.КонтекстПроверкиУдостоверяющегоЦентраСертификата();
	КонтекстПроверки.ДанныеУдостоверяющегоЦентра = ДанныеУдостоверяющегоЦентра;
	КонтекстПроверки.НаименованиеУдостоверяющегоЦентра = ДанныеДляПроверкиУдостоверяющегоЦентра.НаименованиеУдостоверяющегоЦентра;
	КонтекстПроверки.ЗначенияПоиска = ДанныеДляПроверкиУдостоверяющегоЦентра.ЗначенияПоиска;
	КонтекстПроверки.НаДату = ?(НаДату = Неопределено, ТекущаяДатаСеанса(), НаДату);
	КонтекстПроверки.ДобавкаВремени = ДобавкаВремени();
	КонтекстПроверки.ЭтоПроверкаПодписи = ЭтоПроверкаПодписи;
	
	Если СвойстваСертификата = Неопределено Тогда
		КонтекстПроверки.СвойстваСертификата = ЭлектроннаяПодпись.СвойстваСертификата(СертификатКриптографии);
	Иначе
		КонтекстПроверки.СвойстваСертификата = СвойстваСертификата;
	КонецЕсли;
	
	Результат = МодульЭлектроннаяПодписьКлиентСерверЛокализация.РезультатПроверкиУдостоверяющегоЦентраСертификата(
		СертификатКриптографии, КонтекстПроверки);
		
	Если ЗначениеЗаполнено(Результат.Предупреждение.Причина) Тогда
		Результат.Предупреждение.Причина = СтроковыеФункции.ФорматированнаяСтрока(Результат.Предупреждение.Причина);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Результат.Предупреждение.Решение) Тогда
		Результат.Предупреждение.Решение = СтроковыеФункции.ФорматированнаяСтрока(Результат.Предупреждение.Решение);
	КонецЕсли;
	
	// Конец Локализация

	Возврат Результат;
	
КонецФункции

// Только для внутреннего использования.
Процедура ИзменитьОтметкуОНапоминании(Сертификат, Напомнить, ИдентификаторНапоминания) Экспорт
	
	ТекущийПользователь = Пользователи.ТекущийПользователь();
	
	ДоступныНапоминанияПользователя = Ложь;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.НапоминанияПользователя") Тогда
		МодульНапоминанияПользователя = ОбщегоНазначения.ОбщийМодуль("НапоминанияПользователя");
		ДоступныНапоминанияПользователя = МодульНапоминанияПользователя.ИспользуютсяНапоминанияПользователя();
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	НаборЗаписей = РегистрыСведений.ОповещенияПользователейСертификатов.СоздатьНаборЗаписей();
	НаборЗаписей.Отбор.Сертификат.Установить(Сертификат);
	НаборЗаписей.Отбор.Пользователь.Установить(ТекущийПользователь); 
	
	Запись = НаборЗаписей.Добавить();
	Запись.Сертификат = Сертификат;
	Запись.Пользователь = ТекущийПользователь;
	Запись.Оповещен = Не Напомнить;
	Если ДоступныНапоминанияПользователя Тогда
		НаборЗаписей.ДополнительныеСвойства.Вставить("ИдентификаторНапоминания", ИдентификаторНапоминания);
	КонецЕсли;
	НаборЗаписей.Записать();
	
	УстановитьПривилегированныйРежим(Ложь);
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ИзменитьРегламентноеЗаданиеПродлениеДостоверностиПодписей(УсовершенствоватьПодписиАвтоматически = Неопределено,
	ДобавлятьМеткиВремениАвтоматически = Неопределено, ТипПодписиКриптографииПоУмолчанию = Неопределено) Экспорт

	ПараметрыЗадания = Новый Структура;
	ПараметрыЗадания.Вставить("Метаданные", Метаданные.РегламентныеЗадания.ПродлениеДостоверностиПодписей);
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		ПараметрыЗадания.Вставить("ИмяМетода", Метаданные.РегламентныеЗадания.ПродлениеДостоверностиПодписей.ИмяМетода);
	КонецЕсли;
	
	Если УсовершенствоватьПодписиАвтоматически = Неопределено Тогда
		УсовершенствоватьПодписиАвтоматически = Константы.УсовершенствоватьПодписиАвтоматически.Получить();
	КонецЕсли;
	
	Если ДобавлятьМеткиВремениАвтоматически = Неопределено Тогда
		ДобавлятьМеткиВремениАвтоматически = Константы.ДобавлятьМеткиВремениАвтоматически.Получить();
	КонецЕсли;
	
	Если УсовершенствоватьПодписиАвтоматически = 1 И ТипПодписиКриптографииПоУмолчанию = Неопределено Тогда
		ТипПодписиКриптографииПоУмолчанию = Константы.ТипПодписиКриптографииПоУмолчанию.Получить();
	КонецЕсли;
		
	Если Не ОбщегоНазначения.РазделениеВключено() Тогда
		Использование = ДобавлятьМеткиВремениАвтоматически 
			Или УсовершенствоватьПодписиАвтоматически = 1 
				И (ТипПодписиКриптографииПоУмолчанию = Перечисления.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST
					Или ТипПодписиКриптографииПоУмолчанию = Перечисления.ТипыПодписиКриптографии.АрхивнаяCAdESAv3)
	Иначе
		// В модели сервиса можно только усовершенствовать до CAdES-T.
		Использование = УсовершенствоватьПодписиАвтоматически = 1 
				И ТипПодписиКриптографииПоУмолчанию = Перечисления.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	
	СписокЗаданий = РегламентныеЗаданияСервер.НайтиЗадания(ПараметрыЗадания);
	Если СписокЗаданий.Количество() = 0 Тогда
		ПараметрыЗадания.Вставить("Использование", Использование);
		РегламентныеЗаданияСервер.ДобавитьЗадание(ПараметрыЗадания);
	Иначе
		ПараметрыЗадания = Новый Структура("Использование", Использование);
		Для Каждого Задание Из СписокЗаданий Цикл
			РегламентныеЗаданияСервер.ИзменитьЗадание(Задание, ПараметрыЗадания);
		КонецЦикла;
	КонецЕсли;

КонецПроцедуры

// Для формы общих настроек подсистемы Администрирование.
// 
// Параметры:
//  Форма - ФормаКлиентскогоПриложения - см. Обработка.ПанельАдминистрированияБСП.Формы.ОбщиеНастройки
//  РеквизитПутьКДанным - Строка - путь к данным реквизита, который изменили на форме
//
Процедура НастроитьФормуОбщихНастроек(Форма, РеквизитПутьКДанным) Экспорт
	
	Элементы = Форма.Элементы;
	НаборКонстант = Форма.НаборКонстант;
	ОбщиеНастройки = ЭлектроннаяПодпись.ОбщиеНастройки();
	ДоступнаУсовершенствованнаяПодпись = ОбщиеНастройки.ДоступнаУсовершенствованнаяПодпись;
	
	Если ОбщегоНазначения.РазделениеВключено() 
		И (РеквизитПутьКДанным = "НаборКонстант.ИспользоватьЭлектронныеПодписи"
			Или РеквизитПутьКДанным = "НаборКонстант.ИспользоватьШифрование"
			Или РеквизитПутьКДанным = "НаборКонстант.ИспользоватьСервисDSS"
			Или РеквизитПутьКДанным = "") Тогда
				
		Элементы.ПроверятьЭлектронныеПодписиНаСервере.Видимость = ИспользоватьСервисОблачнойПодписи()
			Или ИспользоватьЭлектроннуюПодписьВМоделиСервиса();
		
	КонецЕсли;

	Если РеквизитПутьКДанным = "НаборКонстант.ИспользоватьЭлектронныеПодписи" Или РеквизитПутьКДанным
		= "НаборКонстант.ИспользоватьШифрование" Или РеквизитПутьКДанным = "" Тогда

		Элементы.НастройкиЭлектроннойПодписиИШифрования.Доступность = НаборКонстант.ИспользоватьЭлектронныеПодписи
			Или НаборКонстант.ИспользоватьШифрование;
		Элементы.ГруппаУсовершенствованнаяПодпись.Доступность = НаборКонстант.ИспользоватьЭлектронныеПодписи;
		Элементы.ГруппаПроверятьПодписиНаСервере.Доступность = НаборКонстант.ИспользоватьЭлектронныеПодписи
			Или НаборКонстант.ИспользоватьШифрование;

		Если НаборКонстант.ИспользоватьЭлектронныеПодписи И (РеквизитПутьКДанным
			= "НаборКонстант.ИспользоватьЭлектронныеПодписи" Или РеквизитПутьКДанным = "") Тогда
			Если ДоступнаУсовершенствованнаяПодпись Тогда
				Форма.КонстантаАдресаСерверовМетокВремени = СтрСоединить(ОбщиеНастройки.АдресаСерверовМетокВремени, Символы.ПС);
				Форма.КонстантаУсовершенствоватьПодписиАвтоматически = Константы.УсовершенствоватьПодписиАвтоматически.Получить();
				Форма.КонстантаДобавлятьМеткиВремениАвтоматически = Константы.ДобавлятьМеткиВремениАвтоматически.Получить();
				Форма.КонстантаУсовершенствоватьПодписиСДаты = Константы.УсовершенствоватьПодписиСДаты.Получить();
				ТипПодписи = Константы.ТипПодписиКриптографииПоУмолчанию.Получить();
				Форма.КонстантаТипПодписиКриптографииПоУмолчанию = ТипПодписи;
				УстановитьЗаголовокПодсказкиУсовершенствования(Форма, ТипПодписи);
			КонецЕсли;
			Если Элементы.СоздаватьЭлектронныеПодписиНаСервере.Видимость Тогда
				Форма.КонстантаСоздаватьЭлектронныеПодписиНаСервере = Константы.СоздаватьЭлектронныеПодписиНаСервере.Получить();
			КонецЕсли;
			Если Элементы.ПроверятьЭлектронныеПодписиНаСервере.Видимость Тогда
				Форма.КонстантаПроверятьЭлектронныеПодписиНаСервере = Константы.ПроверятьЭлектронныеПодписиНаСервере.Получить();
			КонецЕсли;
		КонецЕсли;
		
		УстановитьЗаголовокЭлектроннаяПодписьНаСервере(Форма);
		
	ИначеЕсли (РеквизитПутьКДанным = "КонстантаТипПодписиКриптографииПоУмолчанию" Или РеквизитПутьКДанным
		= "КонстантаУсовершенствоватьПодписиАвтоматически") И ДоступнаУсовершенствованнаяПодпись Тогда
		
		Форма.КонстантаУсовершенствоватьПодписиАвтоматически = Константы.УсовершенствоватьПодписиАвтоматически.Получить();
		ТипПодписи = Константы.ТипПодписиКриптографииПоУмолчанию.Получить();
		Форма.КонстантаТипПодписиКриптографииПоУмолчанию = ТипПодписи;
		УстановитьЗаголовокПодсказкиУсовершенствования(Форма, ТипПодписи);
		
	КонецЕсли;

	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодписьСервисаDSS")
	 И ДоступнаУсовершенствованнаяПодпись
		И (РеквизитПутьКДанным = "НаборКонстант.ИспользоватьСервисDSS" Или РеквизитПутьКДанным = "") Тогда

		Если ОбщегоНазначения.РазделениеВключено() Тогда
			
			ЭтоМодельСервисаСДоступнымУсовершенствованием = ОбщиеНастройки.ЭтоМодельСервисаСДоступнымУсовершенствованием;
			Элементы.ГруппаАвтоматическаяОбработкаПодписей.Видимость = ЭтоМодельСервисаСДоступнымУсовершенствованием;
			Элементы.ГруппаДобавлятьМеткиАвтоматически.Видимость = Ложь;
			Элементы.ТипПодписиКриптографииПоУмолчанию.ОтображениеПодсказки = ОтображениеПодсказки.ОтображатьСнизу;
			Если ЭтоМодельСервисаСДоступнымУсовершенствованием Тогда
				Элементы.ТипПодписиКриптографииПоУмолчанию.Видимость = Истина;
				Элементы.ТипПодписиКриптографииПоУмолчанию1.Видимость = Ложь;
				
				ЗаполнитьСписокТиповПодписейКриптографии(
					Элементы.ТипПодписиКриптографииПоУмолчанию.СписокВыбора, "Настройки");
				Элементы.ТипПодписиКриптографииПоУмолчаниюРасширеннаяПодсказка.Заголовок = СтроковыеФункции.ФорматированнаяСтрока(
						НСтр(
					"ru = 'В приложении в Интернете архивная подпись по умолчанию недоступна, этот тип подписи можно выбрать при подписании <a href=%1>сертификатом</a>, установленным на компьютер при установленной <a href=Программы>программе электронной подписи</a>.'"), "Сертификаты");
			Иначе
				Элементы.ТипПодписиКриптографииПоУмолчанию.Видимость = Ложь;
				Элементы.ТипПодписиКриптографииПоУмолчанию1.Видимость = Истина;
				Элементы.ТипПодписиКриптографииПоУмолчанию1РасширеннаяПодсказка.Заголовок = СтроковыеФункции.ФорматированнаяСтрока(
						НСтр(
					"ru = 'В приложении в Интернете по умолчанию установлен тип подписи Базовая, типы подписи с метками времени можно выбрать при подписании <a href=%1>сертификатом</a>, установленным на компьютер при установленной <a href=Программы>программе электронной подписи</a>.'"), "Сертификаты");
			КонецЕсли;
			
		Иначе
			
			ЗаполнитьСписокТиповПодписейКриптографии(
					Элементы.ТипПодписиКриптографииПоУмолчанию.СписокВыбора, "Настройки");
			Элементы.ТипПодписиКриптографииПоУмолчанию.ОтображениеПодсказки = ОтображениеПодсказки.Нет;
			Элементы.ТипПодписиКриптографииПоУмолчанию.Видимость = Истина;
			Элементы.ТипПодписиКриптографииПоУмолчанию1.Видимость = Ложь;
			
		КонецЕсли;
	Иначе
		
		Элементы.ТипПодписиКриптографииПоУмолчанию.ОтображениеПодсказки = ОтображениеПодсказки.Нет;
		
		Если РеквизитПутьКДанным = "" И ДоступнаУсовершенствованнаяПодпись Тогда
			Элементы.ТипПодписиКриптографииПоУмолчанию.Видимость = Истина;
			Элементы.ТипПодписиКриптографииПоУмолчанию1.Видимость = Ложь;
			ЗаполнитьСписокТиповПодписейКриптографии(
					Элементы.ТипПодписиКриптографииПоУмолчанию.СписокВыбора, "Настройки");
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Возвращает выборку сертификатов физических лиц.
// 
// Параметры:
//  ФизическиеЛица - Массив из ОпределяемыйТип.ФизическоеЛицо
// 
// Возвращаемое значение:
//   ВыборкаИзРезультатаЗапроса:
//     * Сертификат - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//     * ФизическоеЛицо - ОпределяемыйТип.ФизическоеЛицо
//
Функция СертификатыФизическихЛиц(ФизическиеЛица) Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	СертификатыКлючейЭлектроннойПодписиИШифрования.Ссылка КАК Сертификат,
	|	СертификатыКлючейЭлектроннойПодписиИШифрования.ФизическоеЛицо КАК ФизическоеЛицо
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК СертификатыКлючейЭлектроннойПодписиИШифрования
	|ГДЕ
	|	СертификатыКлючейЭлектроннойПодписиИШифрования.ФизическоеЛицо В(&МассивФизическихЛиц)
	|	И НЕ СертификатыКлючейЭлектроннойПодписиИШифрования.ПометкаУдаления
	|	И СертификатыКлючейЭлектроннойПодписиИШифрования.ДействителенДо > &ТекущаяДатаСеанса";

	Запрос.УстановитьПараметр("МассивФизическихЛиц", ФизическиеЛица);
	Запрос.УстановитьПараметр("ТекущаяДатаСеанса", ТекущаяДатаСеанса());
	РезультатЗапроса = Запрос.Выполнить();

	Возврат РезультатЗапроса.Выбрать();

КонецФункции

// Возвращает выборку сертификатов физических лиц пользователей.
// 
// Параметры:
//  Пользователи - Массив из СправочникСсылка.Пользователи
// 
// Возвращаемое значение:
//   ВыборкаИзРезультатаЗапроса:
//     * Сертификат - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//     * Пользователь - СправочникСсылка.Пользователи
//
Функция СертификатыФизическихЛицПользователей(Пользователи) Экспорт

	Запрос = Новый Запрос;
	Запрос.Текст = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	СертификатыКлючейЭлектроннойПодписиИШифрования.Ссылка КАК Сертификат,
	|	ПользователиСправочник.Ссылка КАК Пользователь
	|ИЗ
	|	Справочник.Пользователи КАК ПользователиСправочник
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК
	|			СертификатыКлючейЭлектроннойПодписиИШифрования
	|		ПО (СертификатыКлючейЭлектроннойПодписиИШифрования.ФизическоеЛицо = ПользователиСправочник.ФизическоеЛицо
	|		И ПользователиСправочник.Ссылка В (&МассивПользователей)
	|		И ПользователиСправочник.ФизическоеЛицо <> &ПустоеФизическоеЛицо
	|		И НЕ СертификатыКлючейЭлектроннойПодписиИШифрования.ПометкаУдаления
	|		И СертификатыКлючейЭлектроннойПодписиИШифрования.ДействителенДо > &ТекущаяДатаСеанса)";

	ТипыФизическоеЛицо = Метаданные.ОпределяемыеТипы.ФизическоеЛицо.Тип.Типы();
	Если ТипыФизическоеЛицо[0] <> Тип("Строка") Тогда
		Запрос.УстановитьПараметр("ПустоеФизическоеЛицо", Новый (ТипыФизическоеЛицо[0]));
	Иначе
		Запрос.УстановитьПараметр("ПустоеФизическоеЛицо", "");
	КонецЕсли;

	Запрос.УстановитьПараметр("ТекущаяДатаСеанса", ТекущаяДатаСеанса());
	Запрос.УстановитьПараметр("МассивПользователей", Пользователи);
	РезультатЗапроса = Запрос.Выполнить();

	Возврат РезультатЗапроса.Выбрать();

КонецФункции

// Возвращает возможность показа ссылки на инструкцию по типичным проблемам при работе с программами 
// в зависимости от локализации конфигурации.
// 
// Возвращаемое значение:
//  Булево
//
Функция ВидимостьСсылкиНаИнструкциюПоТипичнымПроблемамПриРаботеСПрограммами() Экспорт
	
	НавигационнаяСсылка = "";
	ЭлектроннаяПодписьКлиентСерверЛокализация.ПриОпределенииСсылкиНаИнструкциюПоТипичнымПроблемамПриРаботеСПрограммами(
		НавигационнаяСсылка);
	Возврат Не ПустаяСтрока(НавигационнаяСсылка);
	
КонецФункции

Функция ПолучитьДанныеКомпоненты(ИмяМакета) Экспорт
	Возврат Справочники.СертификатыКлючейЭлектроннойПодписиИШифрования.ПолучитьМакет(ИмяМакета);
КонецФункции

#Область ПоставляемыеДанные

// См. ПоставляемыеДанныеПереопределяемый.ПолучитьОбработчикиПоставляемыхДанных
Процедура ПриОпределенииОбработчиковПоставляемыхДанных(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.ВидДанных = "ОшибкиКриптографии3";
	Обработчик.КодОбработчика = "ОшибкиКриптографии";
	Обработчик.Обработчик = ЭлектроннаяПодписьСлужебный;
	
КонецПроцедуры

// Вызывается при получении уведомления о новых данных.
// В теле следует проверить, необходимы ли эти данные приложению, 
// и если да - установить флажок Загружать.
// 
// Параметры:
//   Дескриптор - ОбъектXDTO
//   Загружать - Булево - Истина, если загружать, Ложь - иначе.
//
Процедура ДоступныНовыеДанные(Знач Дескриптор, Загружать) Экспорт
	
	Загружать = Дескриптор.DataType = "ОшибкиКриптографии3";
	
КонецПроцедуры

// Вызывается после вызова ДоступныНовыеДанные, позволяет разобрать данные.
//
// Параметры:
//   Дескриптор - ОбъектXDTO
//   ПутьКФайлу - Строка - полное имя извлеченного файла. Файл будет автоматически удален 
//                  после завершения процедуры. Если в менеджере сервиса не был
//                  указан файл - значение аргумента равно Неопределено.
//
Процедура ОбработатьНовыеДанные(Знач Дескриптор, Знач ПутьКФайлу) Экспорт
	
	Если Дескриптор.DataType = "ОшибкиКриптографии3" Тогда
		ЗаписатьДанныеКлассификатора(Новый ДвоичныеДанные(ПутьКФайлу));
	КонецЕсли;
	
КонецПроцедуры

// Вызывается при отмене обработки данных в случае сбоя.
//
// Параметры:
//   Дескриптор - ОбъектXDTO
//
Процедура ОбработкаДанныхОтменена(Знач Дескриптор) Экспорт 
	
КонецПроцедуры

#КонецОбласти

#Область ОблачнаяПодпись

// Определяет доступность подсистемы облачной подписи
//
// Возвращаемое значение:
//  Булево
//
Функция ИспользоватьСервисОблачнойПодписи() Экспорт
	
	Результат = Ложь;
	
	// Локализация
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодписьСервисаDSS") Тогда
		МодульСервисКриптографииDSS = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSS");
		Результат = МодульСервисКриптографииDSS.ИспользоватьСервисОблачнойПодписи();
	КонецЕсли;
	// Конец Локализация
	
	Возврат Результат;
	
КонецФункции

// Определяет тип программы облачной подписи.
//
// Возвращаемое значение:
//  Неопределено 
//  Тип
//
Функция ТипПрограммыСервисаПодписи() Экспорт
	
	Результат = Неопределено;
	
	// Локализация
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодписьСервисаDSS") Тогда
		МодульСервисКриптографииDSSКлиентСервер = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSSКлиентСервер");
		Результат = МодульСервисКриптографииDSSКлиентСервер.ПолучитьТипОблачнойПодписи();
	КонецЕсли;
	// Конец Локализация
	
	Возврат Результат;
	
КонецФункции

#КонецОбласти

#Область ОбработчикиСобытийПодсистемКонфигурации

// См. ОбновлениеИнформационнойБазыБСП.ПриДобавленииОбработчиковОбновления.
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
	
	Обработчик = Обработчики.Добавить();
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.Процедура = "Справочники.ПрограммыЭлектроннойПодписиИШифрования.ЗаполнитьНачальныеНастройки";
	Обработчик.РежимВыполнения = "Монопольно";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.6.20";
	Обработчик.Процедура = "ЭлектроннаяПодписьСлужебный.ЗаменитьРольДобавлениеИзменениеЭлектронныхПодписейИШифрование";
	Обработчик.РежимВыполнения = "Оперативно";
	
	Если Метаданные.Обработки.Найти("ПрограммыЭлектроннойПодписиИШифрования") <> Неопределено Тогда
		Обработчик = Обработчики.Добавить();
		Обработчик.Версия = "3.1.6.69";
		Обработчик.Комментарий = НСтр("ru = 'Обновление справочника Программы электронной подписи и шифрования.'");
		Обработчик.Процедура = "Обработки.ПрограммыЭлектроннойПодписиИШифрования.ОбновитьНаименованиеВстроенногоКриптопровайдера";
		Обработчик.РежимВыполнения = "Оперативно";
	КонецЕсли;
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.6.128";
	Обработчик.НачальноеЗаполнение = Истина;
	Обработчик.Комментарий = НСтр("ru = 'Заполнение настроек для усовершенствования подписей.'");
	Обработчик.Процедура = "ЭлектроннаяПодписьСлужебный.ЗаполнитьНастройкиДляУсовершенствованияПодписей";
	Обработчик.РежимВыполнения = "Оперативно";
	
	// Локализация
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.6.180";
	Обработчик.Комментарий = НСтр("ru = 'Устанавливает стандартные адреса серверов меток времени ФНС России и Удостоверяющего Центра ООО «Научно-производственный центр ""1С""» для удобной работы с метками доверенного времени в электронной подписи.'");
	Обработчик.Процедура = "ЭлектроннаяПодписьСлужебный.ЗаполнитьАдресаСерверовМетокВремени";
	Обработчик.РежимВыполнения = "Оперативно";
	// Конец Локализация
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.8.58";
	Обработчик.Комментарий =
		НСтр("ru = 'Устанавливает режим использования Настроена в программах электронной подписи и шифрования.'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("ddaf9603-7641-470b-93cc-8754c9a64a99");
	Обработчик.Процедура = "Справочники.ПрограммыЭлектроннойПодписиИШифрования.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.ПрограммыЭлектроннойПодписиИШифрования.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты      = "Справочник.ПрограммыЭлектроннойПодписиИШифрования";
	Обработчик.ИзменяемыеОбъекты    = "Справочник.ПрограммыЭлектроннойПодписиИШифрования";
	Обработчик.ПроцедураПроверки    = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	
	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.9.122";
	Обработчик.Комментарий = НСтр("ru = 'Удаление путей из заполненных имен файлов подписей. Заполнение идентификатора подписи в регистре Электронные подписи.'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("927d1ffb-682a-474d-b3ea-5a40fd20ff08");
	Обработчик.Процедура = "РегистрыСведений.ЭлектронныеПодписи.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "РегистрыСведений.ЭлектронныеПодписи.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты      = "РегистрСведений.ЭлектронныеПодписи";
	Обработчик.ИзменяемыеОбъекты    = "РегистрСведений.ЭлектронныеПодписи";
	Обработчик.ПроцедураПроверки    = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
			Обработчик.ПриоритетыВыполнения = ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика();
			Приоритет = Обработчик.ПриоритетыВыполнения.Добавить();
			Приоритет.Порядок = "После";
			Приоритет.Процедура = "РаботаСФайлами.ПеренестиЭлектронныеПодписиИСертификатыШифрованияВРегистрыСведений";
	КонецЕсли;

	Обработчик = Обработчики.Добавить();
	Обработчик.Версия = "3.1.9.234";
	Обработчик.Комментарий = НСтр(
		"ru = 'Перенос оповещений об окончании срока действия сертификата, данных заявлений в регистры сведений, заполнение срока действия сертификата с учетом срока действия закрытого ключа.'");
	Обработчик.Идентификатор = Новый УникальныйИдентификатор("a17c1765-820e-4886-9423-ffc1267d7ff1");
	Обработчик.Процедура = "Справочники.СертификатыКлючейЭлектроннойПодписиИШифрования.ОбработатьДанныеДляПереходаНаНовуюВерсию";
	Обработчик.РежимВыполнения = "Отложенно";
	Обработчик.ПроцедураЗаполненияДанныхОбновления = "Справочники.СертификатыКлючейЭлектроннойПодписиИШифрования.ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию";
	Обработчик.ЧитаемыеОбъекты      = "Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования";
	ИзменяемыеОбъекты = Новый Массив;
	ИзменяемыеОбъекты.Добавить("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования");
	ИзменяемыеОбъекты.Добавить("РегистрСведений.ОповещенияПользователейСертификатов");
	Если Метаданные.РегистрыСведений.Найти("ЗаявленияНаВыпускСертификата") <> Неопределено Тогда
		ИзменяемыеОбъекты.Добавить("РегистрСведений.ЗаявленияНаВыпускСертификата");
	КонецЕсли;
	Обработчик.ИзменяемыеОбъекты = СтрСоединить(ИзменяемыеОбъекты, ",");
	Обработчик.БлокируемыеОбъекты = "Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования";
	Обработчик.ПроцедураПроверки    = "ОбновлениеИнформационнойБазы.ДанныеОбновленыНаНовуюВерсиюПрограммы";
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПереименованийОбъектовМетаданных.
Процедура ПриДобавленииПереименованийОбъектовМетаданных(Итог) Экспорт
	
	Библиотека = "СтандартныеПодсистемы";
	
	СтароеИмя = "Роль.ИспользованиеЭЦП";
	НовоеИмя  = "Роль.ИспользованиеЭП";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "2.2.1.7", СтароеИмя, НовоеИмя, Библиотека);
	
	СтароеИмя = "Подсистема.СтандартныеПодсистемы.Подсистема.ЭлектроннаяЦифроваяПодпись";
	НовоеИмя  = "Подсистема.СтандартныеПодсистемы.Подсистема.ЭлектроннаяПодпись";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "2.2.1.7", СтароеИмя, НовоеИмя, Библиотека);
	
	СтароеИмя = "Роль.ИспользованиеЭП";
	НовоеИмя  = "Роль.ИспользованиеЭлектроннойПодписиИШифрования";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "2.3.1.10", СтароеИмя, НовоеИмя, Библиотека);
	
	СтароеИмя = "Роль.ИспользованиеЭлектроннойПодписиИШифрования";
	НовоеИмя  = "Роль.ДобавлениеИзменениеЭлектронныхПодписейИШифрование";
	ОбщегоНазначения.ДобавитьПереименование(Итог, "2.3.3.2", СтароеИмя, НовоеИмя, Библиотека);
	
КонецПроцедуры

// См. ОбщегоНазначенияПереопределяемый.ПриДобавленииПараметровРаботыКлиента.
Процедура ПриДобавленииПараметровРаботыКлиента(Параметры) Экспорт
	
	Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
		НастройкиПодсистемы = Новый Структура;
		НастройкиПодсистемы.Вставить("ПерсональныеНастройки", ЭлектроннаяПодпись.ПерсональныеНастройки());
		НастройкиПодсистемы.Вставить("ОбщиеНастройки",        ЭлектроннаяПодпись.ОбщиеНастройки());
		НастройкиПодсистемы = Новый ФиксированнаяСтруктура(НастройкиПодсистемы);
		Параметры.Вставить("ЭлектроннаяПодпись", НастройкиПодсистемы);
	КонецЕсли;
	
КонецПроцедуры

// См. ОчередьЗаданийПереопределяемый.ПриПолученииСпискаШаблонов.
Процедура ПриПолученииСпискаШаблонов(ШаблоныЗаданий) Экспорт
	
	ШаблоныЗаданий.Добавить(Метаданные.РегламентныеЗадания.ПродлениеДостоверностиПодписей.Имя);
	
КонецПроцедуры

// См. ОчередьЗаданийПереопределяемый.ПриОпределенииПсевдонимовОбработчиков.
Процедура ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам) Экспорт
	
	СоответствиеИменПсевдонимам.Вставить(Метаданные.РегламентныеЗадания.ПродлениеДостоверностиПодписей.ИмяМетода);
	
	Если Метаданные.Обработки.Найти("ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата") <> Неопределено Тогда
		ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата =
			ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(
				"Обработка.ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата");
		ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата.ПриОпределенииПсевдонимовОбработчиков(СоответствиеИменПсевдонимам)
	КонецЕсли;
	
КонецПроцедуры

// См. ЗагрузкаДанныхИзФайлаПереопределяемый.ПриОпределенииСправочниковДляЗагрузкиДанных.
Процедура ПриОпределенииСправочниковДляЗагрузкиДанных(ЗагружаемыеСправочники) Экспорт
	
	// Загрузка в справочник ПрограммыЭлектроннойПодписиИШифрования запрещена.
	СтрокаТаблицы = ЗагружаемыеСправочники.Найти(Метаданные.Справочники.ПрограммыЭлектроннойПодписиИШифрования.ПолноеИмя(), "ПолноеИмя");
	Если СтрокаТаблицы <> Неопределено Тогда 
		ЗагружаемыеСправочники.Удалить(СтрокаТаблицы);
	КонецЕсли;
	
	// Загрузка в справочник СертификатыКлючейЭлектроннойПодписиИШифрования запрещена.
	СтрокаТаблицы = ЗагружаемыеСправочники.Найти(Метаданные.Справочники.СертификатыКлючейЭлектроннойПодписиИШифрования.ПолноеИмя(), "ПолноеИмя");
	Если СтрокаТаблицы <> Неопределено Тогда 
		ЗагружаемыеСправочники.Удалить(СтрокаТаблицы);
	КонецЕсли;
	
КонецПроцедуры

// См. ГрупповоеИзменениеОбъектовПереопределяемый.ПриОпределенииОбъектовСРедактируемымиРеквизитами.
Процедура ПриОпределенииОбъектовСРедактируемымиРеквизитами(Объекты) Экспорт
	Объекты.Вставить(Метаданные.Справочники.ПрограммыЭлектроннойПодписиИШифрования.ПолноеИмя(), "РеквизитыРедактируемыеВГрупповойОбработке");
	Объекты.Вставить(Метаданные.Справочники.СертификатыКлючейЭлектроннойПодписиИШифрования.ПолноеИмя(), "РеквизитыНеРедактируемыеВГрупповойОбработке");
КонецПроцедуры

// Переопределяет исключения неразделенных данных для подсистемы ТехнологияСервиса 
// 
// Параметры:
//  Исключения - Массив из ОбъектМетаданных - исключения.
//
Процедура ПриОпределенииИсключенийНеразделенныхДанных(Исключения) Экспорт

	Исключения.Добавить(Метаданные.РегистрыСведений.СпискиОтзываСертификатов);
	
КонецПроцедуры

// См. ПолучениеВнешнихКомпонентВМоделиСервисаПереопределяемый.ПриОпределенииИспользуемыхВерсийВнешнихКомпонент.
Процедура ПриОпределенииИспользуемыхВерсийВнешнихКомпонент(Идентификаторы) Экспорт

	Идентификаторы.Добавить(ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты().ИмяОбъекта);

КонецПроцедуры

// См. ИнтеграцияПодсистемБСП.ПриОпределенииИспользуемыхВнешнихКомпонент.
Процедура ПриОпределенииИспользуемыхВнешнихКомпонент(Компоненты) Экспорт

	НоваяСтрока = Компоненты.Добавить();
	НоваяСтрока.Идентификатор = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты().ИмяОбъекта;
	НоваяСтрока.ОбновлятьАвтоматически = Истина;
	
КонецПроцедуры

// См. РегламентныеЗаданияПереопределяемый.ПриОпределенииНастроекРегламентныхЗаданий
Процедура ПриОпределенииНастроекРегламентныхЗаданий(Настройки) Экспорт

	Если Метаданные.Обработки.Найти("ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата") <> Неопределено Тогда
		ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата =
			ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(
				"Обработка.ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата");
			ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата.ПриОпределенииНастроекРегламентныхЗаданий(Настройки);
	КонецЕсли;
	
	Настройка = Настройки.Добавить();
	Настройка.РегламентноеЗадание = Метаданные.РегламентныеЗадания.ПродлениеДостоверностиПодписей;
	Настройка.ФункциональнаяОпция = Метаданные.ФункциональныеОпции.ИспользоватьЭлектронныеПодписи;
	
КонецПроцедуры

// См. РаботаСКлассификаторамиПереопределяемый.ПриДобавленииКлассификаторов.
Процедура ПриДобавленииКлассификаторов(Классификаторы) Экспорт
	
	Если Метаданные.ОбщиеМодули.Найти("ЭлектроннаяПодписьСлужебныйЛокализация") = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Описание = Неопределено;
	Если ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.РаботаСКлассификаторами") Тогда
		МодульРаботаСКлассификаторами = ОбщегоНазначения.ОбщийМодуль("РаботаСКлассификаторами");
		Описание = МодульРаботаСКлассификаторами.ОписаниеКлассификатора();
	КонецЕсли;
	Если Описание = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Описание.Идентификатор = ИдентификаторКлассификатора();
	Описание.Наименование = НСтр("ru = 'Список аккредитованных удостоверяющих центров'");
	Описание.ОбновлятьАвтоматически = Истина;
	Описание.ОбщиеДанные = Истина;
	Описание.ОбработкаРазделенныхДанных = Ложь;
	Описание.СохранятьФайлВКэш = Ложь;
	
	Классификаторы.Добавить(Описание);
	
КонецПроцедуры

// См. РаботаСКлассификаторамиПереопределяемый.ПриЗагрузкеКлассификатора.
Процедура ПриЗагрузкеКлассификатора(Идентификатор, Версия, Адрес, Обработан, ДополнительныеПараметры) Экспорт
	
	Если Идентификатор <> ИдентификаторКлассификатора() Тогда
		Возврат;
	КонецЕсли;
	
	Если Метаданные.ОбщиеМодули.Найти("ЭлектроннаяПодписьСлужебныйЛокализация") = Неопределено Тогда
		Обработан = Истина;
		Возврат;
	КонецЕсли;
	
	МодульЭлектроннаяПодписьСлужебныйЛокализация = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьСлужебныйЛокализация");
	МодульЭлектроннаяПодписьСлужебныйЛокализация.ЗагрузитьДанныеАккредитованныхУЦ(Версия, Адрес, Обработан, ДополнительныеПараметры);
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистемы ТекущиеДела.

// Параметры:
//   ТекущиеДела - см. ТекущиеДелаСервер.ТекущиеДела.
//
Процедура ПриЗаполненииСпискаТекущихДел(ТекущиеДела) Экспорт
	
	Если Пользователи.ЭтоСеансВнешнегоПользователя() Тогда
		Возврат;
	КонецЕсли;
	
	МодульТекущиеДелаСервер = ОбщегоНазначения.ОбщийМодуль("ТекущиеДелаСервер");
	
	Разделы = МодульТекущиеДелаСервер.РазделыДляОбъекта(Метаданные.ОбщиеФормы.НастройкиЭлектроннойПодписиИШифрования.ПолноеИмя());
	
	Если ЭлектроннаяПодпись.УправлениеОповещениямиОСертификатах() Тогда
		
		КоличествоСертификатовСИстекающимСрокомДействия = КоличествоСертификатовСИстекающимСрокомДействия(); 
		
		Для Каждого Раздел Из Разделы Цикл
			Дело = ТекущиеДела.Добавить ();
			Дело.Идентификатор  = "ТребуетсяПродлениеСертификата";
			Дело.ЕстьДела       = КоличествоСертификатовСИстекающимСрокомДействия > 0;
			Дело.Представление  = НСтр("ru = 'Требуется продление сертификата'");
			Дело.Количество     = КоличествоСертификатовСИстекающимСрокомДействия;
			Дело.Важное         = Ложь;
			Дело.Форма          = "ОбщаяФорма.НастройкиЭлектроннойПодписиИШифрования";
			Дело.ПараметрыФормы = Новый Структура("СертификатыПоказать", "МоиСертификатыСИстекающимСрокомДействия");
			Дело.Владелец       = Раздел;
		КонецЦикла;
		
		Если ЭлектроннаяПодпись.ОбщиеНастройки().ЗаявлениеНаВыпускСертификатаДоступно Тогда
			
			КоличествоЗаявленийВРаботе = КоличествоЗаявленийВРаботе();
			
			Для Каждого Раздел Из Разделы Цикл
				Дело = ТекущиеДела.Добавить();
				Дело.Идентификатор  = "ЗаявленияНаВыпускСертификатаВРаботе";
				Дело.ЕстьДела       = КоличествоЗаявленийВРаботе > 0;
				Дело.Представление  = НСтр("ru = 'Заявления на выпуск сертификата в работе'");
				Дело.Количество     = КоличествоЗаявленийВРаботе;
				Дело.Важное         = Ложь;
				Дело.Форма          = "ОбщаяФорма.НастройкиЭлектроннойПодписиИШифрования";
				Дело.ПараметрыФормы = Новый Структура("СертификатыПоказать", "МоиЗаявленияВРаботе");
				Дело.Владелец       = Раздел;
			КонецЦикла;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если ЭлектроннаяПодпись.ДоступнаУсовершенствованнаяПодпись() Тогда
		УсовершенствоватьПодписиАвтоматически = Константы.УсовершенствоватьПодписиАвтоматически.Получить();
		
		Если УсовершенствоватьПодписиАвтоматически = 2 Тогда
			
			КоличествоПодписейДляУсовершенствования = КоличествоПодписей("ТребуетсяУсовершенствоватьПодписи");
			Для Каждого Раздел Из Разделы Цикл
				Дело = ТекущиеДела.Добавить ();
				Дело.Идентификатор  = "ТребуетсяУсовершенствоватьПодписи";
				Дело.ЕстьДела       = КоличествоПодписейДляУсовершенствования > 0;
				Дело.Представление  = НСтр("ru = 'Усовершенствовать подписи'");
				Дело.Количество     = КоличествоПодписейДляУсовершенствования;
				Дело.Важное         = Ложь;
				Дело.Форма          = "ОбщаяФорма.ПродлениеСрокаДействияЭлектронныхПодписей";
				Дело.ПараметрыФормы = Новый Структура("РежимПродления", "ТребуетсяУсовершенствоватьПодписи");
				Дело.Владелец       = Раздел;
			КонецЦикла;
			
			КоличествоНеобработанныхПодписей = КоличествоПодписей("НеобработанныеПодписи");
			Для Каждого Раздел Из Разделы Цикл
				Дело = ТекущиеДела.Добавить ();
				Дело.Идентификатор  = "НеобработанныеПодписи";
				Дело.ЕстьДела       = КоличествоНеобработанныхПодписей > 0;
				Дело.Представление  = НСтр("ru = 'Продлить ранее добавленные подписи'");
				Дело.Количество     = КоличествоНеобработанныхПодписей;
				Дело.Важное         = Ложь;
				Дело.Форма          = "ОбщаяФорма.ПродлениеСрокаДействияЭлектронныхПодписей";
				Дело.ПараметрыФормы = Новый Структура("РежимПродления", "НеобработанныеПодписи");
				Дело.Владелец       = Раздел;
			КонецЦикла;
			
		ИначеЕсли УсовершенствоватьПодписиАвтоматически = 1 Или Константы.ДобавлятьМеткиВремениАвтоматически.Получить() Тогда
			
			КоличествоОшибокПриАвтоматическомПродлении = КоличествоПодписей("ОшибкиПриАвтоматическомПродлении");
			Для Каждого Раздел Из Разделы Цикл
				Дело = ТекущиеДела.Добавить ();
				Дело.Идентификатор  = "ОшибкиПриАвтоматическомПродлении";
				Дело.ЕстьДела       = КоличествоОшибокПриАвтоматическомПродлении > 0;
				Дело.Представление  = НСтр("ru = 'Ошибки при автоматическом продлении подписей'");
				Дело.Количество     = КоличествоОшибокПриАвтоматическомПродлении;
				Дело.Важное         = Истина;
				Дело.Форма          = "ОбщаяФорма.ПродлениеСрокаДействияЭлектронныхПодписей";
				Дело.ПараметрыФормы = Новый Структура("РежимПродления", "ОшибкиПриАвтоматическомПродлении");
				Дело.Владелец       = Раздел;
			КонецЦикла;
			
		КонецЕсли;
		
		КоличествоПодписейДляДобавленияАрхивныхМеток = КоличествоПодписей("ТребуетсяДобавитьАрхивныеМетки");
		Для Каждого Раздел Из Разделы Цикл
			Дело = ТекущиеДела.Добавить ();
			Дело.Идентификатор  = "ТребуетсяДобавитьАрхивныеМетки";
			Дело.ЕстьДела       = КоличествоПодписейДляДобавленияАрхивныхМеток > 0;
			Дело.Представление  = НСтр("ru = 'Продлить архивные подписи'");
			Дело.Количество     = КоличествоПодписейДляДобавленияАрхивныхМеток;
			Дело.Важное         = Ложь;
			Дело.Форма          = "ОбщаяФорма.ПродлениеСрокаДействияЭлектронныхПодписей";
			Дело.ПараметрыФормы = Новый Структура("РежимПродления", "ТребуетсяДобавитьАрхивныеМетки");
			Дело.Владелец       = Раздел;
		КонецЦикла;
		
	КонецЕсли;

КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Обработчики событий подсистемы ВариантыОтчетов.

// См. ВариантыОтчетовПереопределяемый.НастроитьВариантыОтчетов.
Процедура ПриНастройкеВариантовОтчетов(Настройки) Экспорт
	
	МодульВариантыОтчетов = ОбщегоНазначения.ОбщийМодуль("ВариантыОтчетов");
	МодульВариантыОтчетов.НастроитьОтчетВМодулеМенеджера(Настройки, Метаданные.Отчеты.ПродлениеСрокаДействияЭлектронныхПодписей);
	
КонецПроцедуры

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Только для внутреннего использования.
// 
// Параметры:
//  КонтейнерПодписи - КонтейнерПодписейКриптографии
//  ДобавкаВремени - Число
//  ДатаСеанса - Дата
// 
// Возвращаемое значение:
//  Структура - параметры подписи криптографии:
//   * ТипПодписи          - ПеречислениеСсылка.ТипыПодписиКриптографии
//   * СрокДействияПоследнейМеткиВремени - Дата, Неопределено - заполняется только с помощью менеджера криптографии.
//   * ДатаПодписиИзМетки - Дата, Неопределено - самый ранний штамп времени.
//   * НеподтвержденнаяДатаПодписи - Дата - неподтвержденная дата подписи.
//                                 - Неопределено - неподтвержденная дата подписи отсутствует в данных подписи.
//   * ДатаПоследнейМеткиВремени - Дата - дата последней метки времени.
//   * Сертификат   - СертификатКриптографии - сертификат подписанта.
//   * ОписаниеСертификата - см. ЭлектроннаяПодписьКлиент.СвойстваСертификата.
//
Функция ПараметрыПодписиКриптографии(КонтейнерПодписи, ДобавкаВремени, ДатаСеанса) Экспорт

	ПараметрыПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеПараметрыПодписиКриптографии();
		
	Подпись = КонтейнерПодписи.Подписи[0];
	
	СертификатСуществует = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатСуществует(Подпись.СертификатПодписи);
	
	Если СертификатСуществует Тогда
		ПараметрыПодписи.ОписаниеСертификата = ЭлектроннаяПодпись.СвойстваСертификата(Подпись.СертификатПодписи);
	КонецЕсли;
	
	Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыПодписиКриптографии(ПараметрыПодписи, Подпись, СертификатСуществует, ДобавкаВремени, ДатаСеанса);
	
КонецФункции

// Извлекает свойства подписи из данных подписи. Если не удалось извлечь все свойства с помощью менеджера криптографии, 
// возвращается часть свойств, которые удалось прочитать из двоичных данных.
// 
// Возвращаемое значение:
//   см. ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатЧтенияСвойствПодписи
//   Соответствие - если передан массив подписей.
//
Функция СвойстваПодписи(Подписи, ПрочитатьСертификаты, ИспользоватьМенеджерКриптографии = Истина) Экспорт
	
	Если ТипЗнч(Подписи) = Тип("Строка") Или ТипЗнч(Подписи) = Тип("ДвоичныеДанные") Тогда
		МассивПодписей = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Подписи);
		Соответствие = Неопределено;
	Иначе
		МассивПодписей = Подписи;
		Соответствие = Новый Соответствие;
	КонецЕсли;
	
	ЧтениеМенеджеромКриптографии = ИспользоватьМенеджерКриптографии 
		И (ЭлектроннаяПодпись.ОбщиеНастройки().ПроверятьЭлектронныеПодписиНаСервере
			Или ЭлектроннаяПодпись.ОбщиеНастройки().СоздаватьЭлектронныеПодписиНаСервере
			Или ОбщегоНазначения.ИнформационнаяБазаФайловая());
	
	Для Каждого Подпись Из МассивПодписей Цикл
	
		Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатЧтенияСвойствПодписи();

		Если ЧтениеМенеджеромКриптографии Тогда
			ОписаниеОшибки = "";
			МенеджерКриптографии = ЭлектроннаяПодпись.МенеджерКриптографии("ЧтениеПодписи", Ложь, ОписаниеОшибки,
				Подпись); // МенеджерКриптографии
			Если МенеджерКриптографии = Неопределено Тогда
				Результат.ТекстОшибки = ОписаниеОшибки;
			Иначе
				Результат = СвойстваПодписиЧтениеМенеджеромКриптографии(Подпись, МенеджерКриптографии, ПрочитатьСертификаты);
				Если Результат.Успех = Истина Тогда
					Если Соответствие = Неопределено Тогда
						Возврат Результат;
					Иначе
						Соответствие.Вставить(Подпись, Результат);
						Продолжить;
					КонецЕсли;
				Иначе
					Результат.Успех = Неопределено;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
		СвойстваПодписиИзДвоичныхДанных = СвойстваПодписиИзДвоичныхДанных(Подпись, ПрочитатьСертификаты);
		ЗаполнитьЗначенияСвойств(Результат, СвойстваПодписиИзДвоичныхДанных, , "Успех, ТекстОшибки");

		Если СвойстваПодписиИзДвоичныхДанных.Успех = Ложь Тогда
			Результат.Успех = Ложь;
			Результат.ТекстОшибки = ?(ПустаяСтрока(Результат.ТекстОшибки), "", Результат.ТекстОшибки + Символы.ПС)
				+ СвойстваПодписиИзДвоичныхДанных.ТекстОшибки;
		КонецЕсли;
		
		Если Соответствие = Неопределено Тогда
			Возврат Результат;
		Иначе
			Соответствие.Вставить(Подпись, Результат);
		КонецЕсли;
	
	КонецЦикла;
	
	Возврат Соответствие;
	
КонецФункции

Функция СвойстваПодписиЧтениеМенеджеромКриптографии(Подпись, МенеджерКриптографии, ПрочитатьСертификаты) Экспорт
	
	Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатЧтенияСвойствПодписи();
	
	ДвоичныеДанные = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДвоичныеДанныеИзДанных(Подпись,
		"ЭлектроннаяПодписьСлужебный.СвойстваПодписиЧтениеМенеджеромКриптографии");
	
	Попытка
		КонтейнерПодписи = МенеджерКриптографии.ПолучитьКонтейнерПодписейКриптографии(ДвоичныеДанные);
	Исключение
		Результат.Успех = Ложь;
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru='При чтении данных подписи: %1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(
					ИнформацияОбОшибке()));
		Возврат Результат;
	КонецПопытки;

	ПараметрыПодписиКриптографии = ПараметрыПодписиКриптографии(
						КонтейнерПодписи, ДобавкаВремени(), ТекущаяДатаСеанса());

	Результат.ТипПодписи = ПараметрыПодписиКриптографии.ТипПодписи;
	Результат.СрокДействияПоследнейМеткиВремени = ПараметрыПодписиКриптографии.СрокДействияПоследнейМеткиВремени;
	Результат.НеподтвержденнаяДатаПодписи = ПараметрыПодписиКриптографии.НеподтвержденнаяДатаПодписи;
	Результат.ДатаПодписиИзМетки = ПараметрыПодписиКриптографии.ДатаПодписиИзМетки;
	Если ПараметрыПодписиКриптографии.ОписаниеСертификата <> Неопределено Тогда
		Результат.Отпечаток = ПараметрыПодписиКриптографии.ОписаниеСертификата.Отпечаток;
		Результат.КомуВыданСертификат = ПараметрыПодписиКриптографии.ОписаниеСертификата.КомуВыдан;
	КонецЕсли;

	Если ПрочитатьСертификаты Тогда
		СтрокаПодписи = КонтейнерПодписи.Подписи[0];
		Если ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатСуществует( 
					СтрокаПодписи.СертификатПодписи) Тогда
			Результат.Сертификат = СтрокаПодписи.СертификатПодписи.Выгрузить();
		КонецЕсли;
		Для Каждого Сертификат Из СтрокаПодписи.СертификатыПроверкиПодписи Цикл
			Если ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатСуществует(Сертификат) Тогда
				Результат.Сертификаты.Добавить(Сертификат.Выгрузить());
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;

	Результат.Успех = Истина;
	Возврат Результат;
	
КонецФункции

Функция СвойстваПодписиИзДвоичныхДанных(Подпись, ПрочитатьСертификаты) Экспорт
	
	Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатЧтенияСвойствПодписи();
	
	Попытка
		СвойстваПодписиИзДвоичныхДанных = ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваПодписиИзДвоичныхДанных(
			Подпись, ДобавкаВремени(), ПрочитатьСертификаты);
		Если Не ЗначениеЗаполнено(СвойстваПодписиИзДвоичныхДанных.ТипПодписи) Тогда
			Результат.ТекстОшибки = НСтр("ru = 'Данные не являются подписью'");
			Результат.Успех = Ложь;
			Возврат Результат;
		КонецЕсли;
	Исключение
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось прочитать свойства подписи: %1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(
			ИнформацияОбОшибке()));
		Возврат Результат;
	КонецПопытки;

	Результат.ТипПодписи = СвойстваПодписиИзДвоичныхДанных.ТипПодписи;

	Если ЗначениеЗаполнено(СвойстваПодписиИзДвоичныхДанных.ДатаПодписания) Тогда
		Результат.НеподтвержденнаяДатаПодписи = СвойстваПодписиИзДвоичныхДанных.ДатаПодписания;
	КонецЕсли;
	Если ЗначениеЗаполнено(СвойстваПодписиИзДвоичныхДанных.ДатаШтампаВремени) Тогда
		Результат.ДатаПодписиИзМетки = СвойстваПодписиИзДвоичныхДанных.ДатаШтампаВремени;
	КонецЕсли;

	Если СвойстваПодписиИзДвоичныхДанных.Сертификаты.Количество() > 0 Тогда
		
		Если СвойстваПодписиИзДвоичныхДанных.Сертификаты.Количество() > 1 Тогда
			Попытка
				Результат.Сертификаты = СертификатыПоПорядкуДоКорневого(
					СвойстваПодписиИзДвоичныхДанных.Сертификаты);
				Результат.Сертификат = Результат.Сертификаты[0];
			Исключение
				Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось прочитать свойства сертификатов: %1'"),
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
			КонецПопытки;
		Иначе
			Результат.Сертификат = СвойстваПодписиИзДвоичныхДанных.Сертификаты[0];
		КонецЕсли;
		
		Попытка
			Сертификат = Новый СертификатКриптографии(Результат.Сертификат);
			Результат.Сертификат = Сертификат.Выгрузить();
			СвойстваСертификата = ЭлектроннаяПодпись.СвойстваСертификата(Сертификат);
			Результат.Отпечаток = СвойстваСертификата.Отпечаток;
			Результат.КомуВыданСертификат = СвойстваСертификата.КомуВыдан;
		Исключение
			Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Не удалось прочитать свойства сертификата: %1'"),
				ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		КонецПопытки;

	КонецЕсли;

	Результат.Успех = ПустаяСтрока(Результат.ТекстОшибки);
	
	Возврат Результат;

КонецФункции

Процедура УстановитьВидимостьСсылкиНаИнструкциюПоРаботеСПрограммами(ЭлементИнструкция) Экспорт
	
	НавигационнаяСсылка = "";
	ЭлектроннаяПодписьКлиентСерверЛокализация.ПриОпределенииСсылкиНаИнструкциюПоРаботеСПрограммами("", НавигационнаяСсылка);
	ЭлементИнструкция.Видимость = Не ПустаяСтрока(НавигационнаяСсылка);
	
КонецПроцедуры

Функция ЗаголовокИнформацииДляПоддержки() Экспорт
	
	Если ВидимостьСсылкиНаИнструкциюПоТипичнымПроблемамПриРаботеСПрограммами() Тогда
		Заголовок = СтроковыеФункции.ФорматированнаяСтрока(
			НСтр("ru = 'При возникновении затруднений ознакомьтесь со списком <a href = %1>типичных проблем при работе с программой электронной подписи и их решений</a>.
				|
				|В иных случаях обратитесь в службу поддержки фирмы ""1С"", предоставив <a href = %2>техническую информацию о возникшей проблеме</a>'"),
				"ТипичныеПроблемы", "ТехническаяИнформация");
	Иначе
		Заголовок = СтроковыеФункции.ФорматированнаяСтрока(
			НСтр("ru = 'Обратитесь в службу поддержки фирмы ""1С"", предоставив <a href = %1>техническую информацию о возникшей проблеме</a>'"),
				"ТехническаяИнформация");
	КонецЕсли;
	
	Возврат Заголовок;
	
КонецФункции

// Определяет внутренний идентификатор классификатора для подсистемы РаботаСКлассификаторами.
//
// Возвращаемое значение:
//  Строка - идентификатор классификатора.
//
Функция ИдентификаторКлассификатора()
	
	МодульЭлектроннаяПодписьСлужебныйЛокализация = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьСлужебныйЛокализация");
	Если МодульЭлектроннаяПодписьСлужебныйЛокализация <> Неопределено Тогда
		Возврат МодульЭлектроннаяПодписьСлужебныйЛокализация.ИдентификаторКлассификатора();
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Только для внутреннего использования.
Функция ОшибкаСертификатПомеченКакОтозванный() Экспорт
	
	ПредставлениеОшибки = Новый Структура;
	ПредставлениеОшибки.Вставить("ТекстОшибки", НСтр("ru='Сертификат помечен в программе как отозванный.'"));
	ПредставлениеОшибки.Вставить("Причина", НСтр("ru='Возможно, подано заявление на отзыв сертификата.'"));
	ПредставлениеОшибки.Вставить("Решение", СтроковыеФункции.ФорматированнаяСтрока(
		НСтр("ru='В меню <b>Еще</b> в <a href=""%1"">карточке сертификата</a> можно снять пометку <b>Сертификат отозван</b>. Но если сертификат отозван в удостоверяющем центре, сделать подпись таким сертификатом будет все равно невозможно.'"),
		"ОткрытьСертификат"));
	Возврат ПредставлениеОшибки;
	
КонецФункции

// Возвращает дополнительные параметры создания менеджера криптографии.
//
// Возвращаемое значение:
//   Структура:
//    * ПоказатьОшибку - Булево - если Истина, тогда будет вызвано исключение, содержащее описание ошибки.
//
//    * ОписаниеОшибки - Строка - возвращаемое описание ошибки, когда функция возвратила значение Неопределено.
//                     - Структура - см. ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок
//
//    * Программа       - Неопределено - возвращает менеджер криптографии первой
//                      программы из справочника для которой удалось его создать.
//                      - СправочникСсылка.ПрограммыЭлектроннойПодписиИШифрования - программа
//                      для которой нужно создать и вернуть менеджер криптографии.
//                      - Структура - см. ЭлектроннаяПодпись.НовоеОписаниеПрограммы
//
//    * АлгоритмПодписи - Строка - если параметр заполнен, возвращает программу с указанным алгоритмом подписи.
//    * Автоопределение - Булево - определять установленные программы.
//
Функция ПараметрыСозданияМенеджераКриптографии() Экспорт
	
	ПараметрыСозданияМенеджераКриптографии = Новый Структура;
	ПараметрыСозданияМенеджераКриптографии.Вставить("Программа", Неопределено);
	ПараметрыСозданияМенеджераКриптографии.Вставить("ПоказатьОшибку", Ложь);
	ПараметрыСозданияМенеджераКриптографии.Вставить("ОписаниеОшибки", "");
	ПараметрыСозданияМенеджераКриптографии.Вставить("АлгоритмПодписи", "");
	ПараметрыСозданияМенеджераКриптографии.Вставить("Автоопределение", Истина);
	
	Возврат ПараметрыСозданияМенеджераКриптографии;
	
КонецФункции

// Возвращает менеджер криптографии (на сервере) для указанной программы.
//
// Параметры:
//  Операция                       - Строка - если не пустая, то должна содержать одну из строк, которые определяют
//                                 операцию для вставки в описание ошибки: Подписание, ПроверкаПодписи, Шифрование,
//                                 Расшифровка, ПроверкаСертификата, ПолучениеСертификатов.
//  ПараметрыМенеджераКриптографии - см. ЭлектроннаяПодписьСлужебный.ПараметрыСозданияМенеджераКриптографии.
//
// Возвращаемое значение:
//   МенеджерКриптографии - менеджер криптографии.
//   Неопределено - произошла ошибка, описание которой в параметре ОписаниеОшибки.
//
Функция МенеджерКриптографии(Операция, ПараметрыСозданияМенеджераКриптографии = Неопределено) Экспорт
	
	Если ПараметрыСозданияМенеджераКриптографии = Неопределено Тогда
		ПараметрыСозданияМенеджераКриптографии = ПараметрыСозданияМенеджераКриптографии();
	КонецЕсли;
	
	Программа = ПараметрыСозданияМенеджераКриптографии.Программа;
	ПоказатьОшибку = ПараметрыСозданияМенеджераКриптографии.ПоказатьОшибку;
	АлгоритмПодписи = ПараметрыСозданияМенеджераКриптографии.АлгоритмПодписи;
		
	ИмяКомпьютера = ИмяКомпьютера();
	ОписаниеОшибок = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок(ИмяКомпьютера);
	Менеджер = НовыйМенеджерКриптографии(Программа,
		ОписаниеОшибок.Ошибки, ПараметрыСозданияМенеджераКриптографии.Автоопределение, АлгоритмПодписи, Операция);
	
	Если Менеджер <> Неопределено Тогда
		Возврат Менеджер;
	КонецЕсли;
	
	Если Операция = "Подписание" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось подписать данные на сервере %1 по причине:'");
		
	ИначеЕсли Операция = "ПроверкаПодписи" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось проверить подпись на сервере %1 по причине:'");
	
	ИначеЕсли Операция = "Шифрование" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось зашифровать данные на сервере %1 по причине:'");
		
	ИначеЕсли Операция = "Расшифровка" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось расшифровать данные на сервере %1 по причине:'");
		
	ИначеЕсли Операция = "ПроверкаСертификата" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось проверить сертификат на сервере %1 по причине:'");
		
	ИначеЕсли Операция = "ПолучениеСертификатов" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось получить сертификаты на сервере %1 по причине:'");
	
	ИначеЕсли Операция = "ЧтениеПодписи" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось прочитать все свойства подписи на сервере %1 по причине:'");
		
	ИначеЕсли Операция = "ПродлениеСрокаДействияПодписи" Тогда
		ЗаголовокОшибки = НСтр("ru = 'Не удалось усовершенствовать подписи на сервере %1 по причине:'");
		
	ИначеЕсли Операция <> "" Тогда
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка вызова функции %1.
			           |Неверное значение параметра Операция ""%2"".'"), "МенеджерКриптографии", Операция);
		
	ИначеЕсли ТипЗнч(ПараметрыСозданияМенеджераКриптографии.ОписаниеОшибки) = Тип("Структура")
		И ПараметрыСозданияМенеджераКриптографии.ОписаниеОшибки.Свойство("ЗаголовокОшибки") Тогда
		
		ЗаголовокОшибки = ПараметрыСозданияМенеджераКриптографии.ОписаниеОшибки.ЗаголовокОшибки;
	Иначе
		ЗаголовокОшибки = НСтр("ru = 'Не удалось выполнить операцию на сервере %1 по причине:'");
	КонецЕсли;
	
	ЗаголовокОшибки = СтрЗаменить(ЗаголовокОшибки, "%1", ИмяКомпьютера);
	ОписаниеОшибок.ЗаголовокОшибки = ЗаголовокОшибки;
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииЗаполнитьПредставлениеОшибок(
		ОписаниеОшибок,
		Программа,
		АлгоритмПодписи,
		Пользователи.ЭтоПолноправныйПользователь(,, Ложь),
		Истина);
	
	Если ТипЗнч(ПараметрыСозданияМенеджераКриптографии.ОписаниеОшибки) = Тип("Структура") Тогда
		ПараметрыСозданияМенеджераКриптографии.ОписаниеОшибки = ОписаниеОшибок;
	Иначе
		ПараметрыСозданияМенеджераКриптографии.ОписаниеОшибки = ОписаниеОшибок.ОписаниеОшибки;
	КонецЕсли;
	
	Если ПоказатьОшибку Тогда
		ВызватьИсключение ОписаниеОшибок.ОписаниеОшибки;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Находит сертификат на компьютере по строке отпечатка.
//
// Параметры:
//   Отпечаток              - Строка - Base64 кодированный отпечаток сертификата.
//   ТолькоВЛичномХранилище - Булево - если Истина, тогда искать в личном хранилище, иначе везде.
//
// Возвращаемое значение:
//   СертификатКриптографии - сертификат электронной подписи и шифрования.
//   Неопределено - сертификат не существует.
//
Функция ПолучитьСертификатПоОтпечатку(Отпечаток, ТолькоВЛичномХранилище,
			ПоказатьОшибку = Истина, Программа = Неопределено, ОписаниеОшибки = "") Экспорт
	
	ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.Программа = Программа;
	ПараметрыСоздания.ПоказатьОшибку = ПоказатьОшибку;
	ПараметрыСоздания.ОписаниеОшибки = ОписаниеОшибки;
	
	МенеджерКриптографии = МенеджерКриптографии("ПолучениеСертификатов", ПараметрыСоздания);
	
	ОписаниеОшибки = ПараметрыСоздания.ОписаниеОшибки;
	Если МенеджерКриптографии = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ТипХранилища = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТипХранилищаДляПоискаСертификата(ТолькоВЛичномХранилище);
	
	Попытка
		ДвоичныеДанныеОтпечатка = Base64Значение(Отпечаток);
	Исключение
		Если ПоказатьОшибку Тогда
			ВызватьИсключение;
		КонецЕсли;
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	КонецПопытки;
	
	Если Не ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		Попытка
			ХранилищеСертификатовКриптографии = МенеджерКриптографии.ПолучитьХранилищеСертификатов(ТипХранилища);
		Исключение
			Если ПоказатьОшибку Тогда
				ВызватьИсключение;
			КонецЕсли;
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
		КонецПопытки;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		Попытка
			Сертификат = ХранилищеСертификатовКриптографии.НайтиПоОтпечатку(ДвоичныеДанныеОтпечатка);
		Исключение
			Если ПоказатьОшибку Тогда
				ВызватьИсключение;
			КонецЕсли;
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
		КонецПопытки;
	КонецЕсли;
	
	Если ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда
		Возврат Сертификат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Сертификат не установлен на сервере по причине:
			           |%1'")
			+ Символы.ПС,
			ПредставлениеОшибки);
	Иначе
		ТекстОшибки = НСтр("ru = 'Сертификат не установлен на сервере.'");
	КонецЕсли;
		
	Если Не Пользователи.ЭтоПолноправныйПользователь(,, Ложь) Тогда
		ТекстОшибки = ТекстОшибки + Символы.ПС + НСтр("ru = 'Обратитесь к администратору.'")
	КонецЕсли;
	
	ТекстОшибки = СокрП(ТекстОшибки);
	
	Если ТипЗнч(ОписаниеОшибки) = Тип("Структура") Тогда
		ОписаниеОшибки = Новый Структура;
		ОписаниеОшибки.Вставить("ОписаниеОшибки", ТекстОшибки);
	Иначе
		ОписаниеОшибки = ПредставлениеОшибки;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Только для внутреннего использования.
Функция ДобавкаВремени() Экспорт
	
	Возврат ТекущаяДатаСеанса() - ТекущаяУниверсальнаяДата();
	
КонецФункции

// Сохраняет настройки текущего пользователя для работы с электронной подписью.
Процедура СохранитьПерсональныеНастройки(ПерсональныеНастройки) Экспорт
	
	КлючПодсистемы = КлючХраненияНастроек();
	
	Для Каждого КлючИЗначение Из ПерсональныеНастройки Цикл
		ОбщегоНазначения.ХранилищеОбщихНастроекСохранить(КлючПодсистемы, КлючИЗначение.Ключ,
			КлючИЗначение.Значение);
	КонецЦикла;
	
КонецПроцедуры

// Ключ, который используется для хранения настроек подсистемы.
Функция КлючХраненияНастроек() Экспорт
	
	Возврат "ЭЦП"; // Не заменять на "ЭП". Используется для обратной совместимости.
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * ТолькоПросмотр     - Булево - если установить Истина, редактирование будет запрещено.
//   * ПроверкаЗаполнения - Булево - если установить Истина, заполнение будет проверяться.
//   * Видимость          - Булево - если установить Истина, реквизит станет невидимым.
//   * ЗначениеЗаполнения - Произвольный - начальное значение реквизита нового объекта.
//                        - Неопределено - заполнение не требуется.
//
Функция НовыеПараметрыРеквизитаСертификата()
	
	Параметры = Новый Структура;
	Параметры.Вставить("ТолькоПросмотр", Ложь);
	Параметры.Вставить("ПроверкаЗаполнения", Ложь);
	Параметры.Вставить("Видимость", Ложь);
	Параметры.Вставить("ЗначениеЗаполнения", Неопределено);
	
	Возврат Параметры;
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * Наименование - см. НовыеПараметрыРеквизитаСертификата
//   * Организация  - см. НовыеПараметрыРеквизитаСертификата
//   * ВводитьПарольВПрограммеЭлектроннойПодписи - см. НовыеПараметрыРеквизитаСертификата
//
Функция НовыеПараметрыРеквизитовСертификата() Экспорт
	
	Возврат Новый Структура;
	
КонецФункции

// Только для внутреннего использования.
// Параметры:
//  Ссылка - СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//  Сертификат - СертификатКриптографии
//  ПараметрыРеквизитов - см. НовыеПараметрыРеквизитовСертификата
//
Процедура ПередНачаломРедактированияСертификатаКлюча(Ссылка, Сертификат, ПараметрыРеквизитов) Экспорт
	
	Таблица = Новый ТаблицаЗначений;
	Таблица.Колонки.Добавить("ИмяРеквизита",       Новый ОписаниеТипов("Строка"));
	Таблица.Колонки.Добавить("ТолькоПросмотр",     Новый ОписаниеТипов("Булево"));
	Таблица.Колонки.Добавить("ПроверкаЗаполнения", Новый ОписаниеТипов("Булево"));
	Таблица.Колонки.Добавить("Видимость",          Новый ОписаниеТипов("Булево"));
	Таблица.Колонки.Добавить("ЗначениеЗаполнения");
	
	ЭлектроннаяПодписьПереопределяемый.ПередНачаломРедактированияСертификатаКлюча(Ссылка, Сертификат, Таблица);
	
	ПараметрыРеквизитов = НовыеПараметрыРеквизитовСертификата();
	
	Для Каждого Строка Из Таблица Цикл
		Параметры = НовыеПараметрыРеквизитаСертификата();
		ЗаполнитьЗначенияСвойств(Параметры, Строка);
		ПараметрыРеквизитов.Вставить(Строка.ИмяРеквизита, Параметры);
	КонецЦикла;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ПроверитьУникальностьПредставления(Представление, СертификатСсылка, Поле, Отказ) Экспорт
	
	Если Не ЗначениеЗаполнено(Представление) Тогда
		Возврат;
	КонецЕсли;
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Ссылка",       СертификатСсылка);
	Запрос.УстановитьПараметр("Наименование", Представление);
	
	Запрос.Текст =
	"ВЫБРАТЬ
	|	ИСТИНА КАК ЗначениеИстина
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
	|ГДЕ
	|	Сертификаты.Ссылка <> &Ссылка
	|	И Сертификаты.Наименование = &Наименование";
	
	Если Не Запрос.Выполнить().Пустой() Тогда
		ТекстСообщения = НСтр("ru = 'Сертификат с таким представлением уже существует.'");
		ОбщегоНазначения.СообщитьПользователю(ТекстСообщения,, Поле,, Отказ);
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
Функция СведенияОПодписиДляЖурналаРегистрации(ДатаПодписи, СвойстваПодписи, ЭтоОшибкаПодписания = Ложь) Экспорт
	
	Если СвойстваПодписи.Свойство("ОписаниеСертификата") И СвойстваПодписи.ОписаниеСертификата <> Неопределено Тогда
		СвойстваСертификата = СвойстваПодписи.ОписаниеСертификата;
	Иначе
		СвойстваСертификата = Новый Структура;
		СвойстваСертификата.Вставить("СерийныйНомер", Base64Значение(""));
		СвойстваСертификата.Вставить("КемВыдан",      "");
		СвойстваСертификата.Вставить("КомуВыдан",     "");
		СвойстваСертификата.Вставить("ДатаНачала",    '00010101');
		СвойстваСертификата.Вставить("ДатаОкончания", '00010101');
		СвойстваСертификата.Вставить("ДействителенДо", '00010101');
		
		Если ТипЗнч(СвойстваПодписи.Сертификат) = Тип("Строка")
		   И ЭтоАдресВременногоХранилища(СвойстваПодписи.Сертификат) Тогда
			Сертификат = ПолучитьИзВременногоХранилища(СвойстваПодписи.Сертификат);
		Иначе
			Сертификат = СвойстваПодписи.Сертификат;
		КонецЕсли;
		
		Если ТипЗнч(Сертификат) = Тип("ДвоичныеДанные") Тогда
			СертификатКриптографии = Новый СертификатКриптографии(Сертификат);
			СвойстваСертификата = ЭлектроннаяПодпись.СвойстваСертификата(СертификатКриптографии);
			
		ИначеЕсли СвойстваПодписи.Свойство("КомуВыданСертификат") Тогда
			СвойстваСертификата.КомуВыдан = СвойстваПодписи.КомуВыданСертификат;
		КонецЕсли;
	КонецЕсли;
	
	Если ЭтоОшибкаПодписания Тогда
		СведенияОПодписи = "";
	Иначе
		СведенияОПодписи = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Дата подписи: %1'"), Формат(ДатаПодписи, "ДЛФ=DT")) + Символы.ПС;
	КонецЕсли;
	
	СведенияОПодписи = СведенияОПодписи + ЭлектроннаяПодписьСлужебныйКлиентСервер.СведенияОСертификатеСтрокой(СвойстваСертификата);
	
	Возврат СведенияОПодписи;
	
КонецФункции

// Только для внутреннего использования.
Процедура ЗарегистрироватьПодписаниеДанныхВЖурнале(ЭлементДанных, ОписаниеОшибки = "") Экспорт
	
	ЭтоОшибкаПодписания = ЗначениеЗаполнено(ОписаниеОшибки);
	
	Если ТипЗнч(ЭлементДанных.СвойстваПодписи) = Тип("Строка") Тогда
		СвойстваПодписи = ПолучитьИзВременногоХранилища(ЭлементДанных.СвойстваПодписи);
	Иначе
		СвойстваПодписи = ЭлементДанных.СвойстваПодписи;
	КонецЕсли;
	
	СообщениеЖурналаРегистрации = СведенияОПодписиДляЖурналаРегистрации(
		СвойстваПодписи.ДатаПодписи, СвойстваПодписи, ЭтоОшибкаПодписания);
	
	Если ЭтоОшибкаПодписания Тогда
		ИмяСобытия = НСтр("ru = 'Электронная подпись.Ошибка подписания данных'",
			ОбщегоНазначения.КодОсновногоЯзыка());
		
		СообщениеЖурналаРегистрации = СообщениеЖурналаРегистрации + "
		|
		|" + ОписаниеОшибки;
	Иначе
		ИмяСобытия = НСтр("ru = 'Электронная подпись.Подписание данных'",
			ОбщегоНазначения.КодОсновногоЯзыка());
	КонецЕсли;
	
	Если ОбщегоНазначения.ЭтоСсылка(ТипЗнч(ЭлементДанных.ПредставлениеДанных)) Тогда
		МетаданныеЭлементаДанных = ЭлементДанных.ПредставлениеДанных.Метаданные();
	Иначе
		МетаданныеЭлементаДанных = Неопределено;
	КонецЕсли;
	
	ЗаписьЖурналаРегистрации(ИмяСобытия,
		УровеньЖурналаРегистрации.Информация,
		МетаданныеЭлементаДанных,
		ЭлементДанных.ПредставлениеДанных,
		СообщениеЖурналаРегистрации);
	
КонецПроцедуры
	
// Только для внутреннего использования.
//
// Параметры:
//  СписокВыбора - СписокЗначений - список для заполнения.
//  Операция     - Строка - "Усовершенствование", "Подписание", "Настройки" - для каких операций формируется список.
//               - Неопределено - (по умолчанию) для формирования полного списка.
//  ТипПодписи   - ПеречислениеСсылка.ТипыПодписиКриптографии - ТипПодписи, от которого зависит, какие подписи доступны
//                                                              для операции.
//
Процедура ЗаполнитьСписокТиповПодписейКриптографии(СписокВыбора, Операция = Неопределено, ТипПодписи = Неопределено) Экспорт
	
	СписокВыбора.Очистить();
	Если Операция <> "Усовершенствование"
		И (Не ЗначениеЗаполнено(ТипПодписи) Или ТипПодписи = Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES) Тогда
		
		СписокВыбора.Добавить(Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='Базовая подпись (%1)
					 |становится недействительной после окончания срока действия сертификата подписанта (обычно в течение 1 года).'"),
			"CAdES-BES"));
	КонецЕсли;

	РазделениеВключено = ОбщегоНазначения.РазделениеВключено();
	ДобавитьТипПодписи = Ложь;
	
	Если РазделениеВключено Тогда
		ЭтоМодельСервисаСДоступнымУсовершенствованием = ЭлектроннаяПодпись.ОбщиеНастройки().ЭтоМодельСервисаСДоступнымУсовершенствованием;
		ДобавитьТипПодписи = ЭтоМодельСервисаСДоступнымУсовершенствованием Или Не Операция = "Настройки";
	Иначе
		Если Не ЗначениеЗаполнено(ТипПодписи) Или ТипПодписи = Перечисления.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST
			И Операция <> "Усовершенствование" Или ТипПодписи = Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES Тогда
			ДобавитьТипПодписи = Истина;
		КонецЕсли;
	КонецЕсли;
	
	Если ДобавитьТипПодписи Тогда
		СписокВыбора.Добавить(Перечисления.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST,
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='Подпись с меткой доверенного времени (%1)
					 |действует после окончания срока действия сертификата подписанта.'"), "CAdES-T"));
	КонецЕсли;

	Если Операция = Неопределено Или Не (РазделениеВключено И Операция = "Настройки") Тогда
		СписокВыбора.Добавить(Перечисления.ТипыПодписиКриптографии.АрхивнаяCAdESAv3,
			СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='Архивная подпись (%1)
					 |содержит полный набор доказательств подлинности, в том числе цепочку сертификатов, и автоматически продлевается.'"),
			"CAdES-A"));
	КонецЕсли;

КонецПроцедуры

// Только для внутреннего использования.
Процедура ОбновитьСписокСертификатов(Сертификаты, СвойстваСертификатовНаКлиенте, КромеУжеДобавленных,
				Личные, Ошибка, БезОтбора, ДополнительныеПараметры = Неопределено) Экспорт
	
	Если ТипЗнч(ДополнительныеПараметры) = Тип("Структура") Тогда
		ОтборПоОрганизации = ДополнительныеПараметры.ОтборПоОрганизации;
		ВыполнятьНаСервере = ДополнительныеПараметры.ВыполнятьНаСервере;
	Иначе
		ОтборПоОрганизации = Неопределено;
		ВыполнятьНаСервере = Неопределено;
	КонецЕсли;
	
	ТаблицаСвойствСертификатов = Новый ТаблицаЗначений;
	ТаблицаСвойствСертификатов.Колонки.Добавить("Отпечаток", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(255)));
	ТаблицаСвойствСертификатов.Колонки.Добавить("КемВыдан");
	ТаблицаСвойствСертификатов.Колонки.Добавить("Представление");
	ТаблицаСвойствСертификатов.Колонки.Добавить("НаКлиенте",            Новый ОписаниеТипов("Булево"));
	ТаблицаСвойствСертификатов.Колонки.Добавить("НаСервере",            Новый ОписаниеТипов("Булево"));
	ТаблицаСвойствСертификатов.Колонки.Добавить("ЭтоЗаявление",         Новый ОписаниеТипов("Булево"));
	ТаблицаСвойствСертификатов.Колонки.Добавить("ВОблачномСервисе",     Новый ОписаниеТипов("Булево"));
	ТаблицаСвойствСертификатов.Колонки.Добавить("ТипРазмещения",        Новый ОписаниеТипов("Число"));
	ТаблицаСвойствСертификатов.Колонки.Добавить("СостояниеСертификата", Новый ОписаниеТипов("Число"));
	ТаблицаСвойствСертификатов.Колонки.Добавить("ЕстьВСправочнике",     Новый ОписаниеТипов("Булево"));
	
	Для Каждого СвойстваСертификата Из СвойстваСертификатовНаКлиенте Цикл
		НоваяСтрока = ТаблицаСвойствСертификатов.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, СвойстваСертификата);
		НоваяСтрока.НаКлиенте = Истина;
	КонецЦикла;
	
	ТаблицаСвойствСертификатов.Индексы.Добавить("Отпечаток");
	
	Если ЭлектроннаяПодпись.СоздаватьЭлектронныеПодписиНаСервере()
	   И ВыполнятьНаСервере <> Ложь Тогда
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ОписаниеОшибки = Ошибка;
		
		МенеджерКриптографии = МенеджерКриптографии("ПолучениеСертификатов", ПараметрыСоздания);
		
		Ошибка = ПараметрыСоздания.ОписаниеОшибки;
		Если МенеджерКриптографии <> Неопределено Тогда
			
			Попытка
				МассивСертификатов = МенеджерКриптографии.ПолучитьХранилищеСертификатов(
					ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты).ПолучитьВсе();
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьСвойстваСертификатов(ТаблицаСвойствСертификатов,
					МассивСертификатов, БезОтбора, ДобавкаВремени(), ТекущаяДатаСеанса());
			Исключение
				ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
				Если ТипЗнч(Ошибка) = Тип("Структура") Тогда
					Ошибка = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок(ИмяКомпьютера());
					Ошибка.ОписаниеОшибки = ОписаниеОшибки;
				Иначе
					Ошибка = ОписаниеОшибки;
				КонецЕсли;
			КонецПопытки;

			Если Не Личные Тогда
				Попытка
					МассивСертификатов = МенеджерКриптографии.ПолучитьХранилищеСертификатов(
						ТипХранилищаСертификатовКриптографии.СертификатыПолучателей).ПолучитьВсе();
					ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьСвойстваСертификатов(ТаблицаСвойствСертификатов,
						МассивСертификатов, БезОтбора, ДобавкаВремени(), ТекущаяДатаСеанса());
				Исключение
					ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
					Если ТипЗнч(Ошибка) = Тип("Структура") Тогда
						Ошибка = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок(ИмяКомпьютера());
						Ошибка.ОписаниеОшибки = ОписаниеОшибки;
					Иначе
						Ошибка = ОписаниеОшибки;
					КонецЕсли;
				КонецПопытки;
			КонецЕсли;
	
		КонецЕсли;
		
	КонецЕсли;
	
	Если ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
		
		МодульХранилищеСертификатов = ОбщегоНазначения.ОбщийМодуль("ХранилищеСертификатов");
		МассивСертификатов = МодульХранилищеСертификатов.Получить("ПерсональныеСертификаты");
		
		ПараметрыДобавленияСвойств = Новый Структура("ВОблачномСервисе", Истина);
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьСвойстваСертификатов(ТаблицаСвойствСертификатов,
			МассивСертификатов, БезОтбора, ДобавкаВремени(), ТекущаяДатаСеанса(), ПараметрыДобавленияСвойств);
		
		Если Не Личные Тогда
			МассивСертификатов = МодульХранилищеСертификатов.Получить("СертификатыПолучателей");
			
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьСвойстваСертификатов(ТаблицаСвойствСертификатов,
				МассивСертификатов, БезОтбора, ДобавкаВремени(), ТекущаяДатаСеанса(), ПараметрыДобавленияСвойств);
		КонецЕсли;
		
	КонецЕсли;
	
	Если ИспользоватьСервисОблачнойПодписи() Тогда
		// Локализация
		МодульСервисКриптографииDSSСлужебный = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSSСлужебный");
		МассивСертификатов = МодульСервисКриптографииDSSСлужебный.ПолучитьДанныеСертификатов(Ложь);
		
		ПараметрыДобавленияСвойств = Новый Структура("ОблачнаяПодпись", Истина);
		
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьСвойстваСертификатов(ТаблицаСвойствСертификатов,
			МассивСертификатов, БезОтбора, ДобавкаВремени(), ТекущаяДатаСеанса(), ПараметрыДобавленияСвойств);
		// Конец Локализация
	КонецЕсли;
	
	ОбработатьДобавленныеСертификаты(ТаблицаСвойствСертификатов, Не БезОтбора И КромеУжеДобавленных, ОтборПоОрганизации);
	
	ТаблицаСвойствСертификатов.Индексы.Добавить("Представление");
	ТаблицаСвойствСертификатов.Сортировать("Представление Возр");
	
	ОбработанныеСтроки  = Новый Соответствие;
	Индекс = 0;
	Отбор = Новый Структура("Отпечаток", "");
	
	Для каждого СвойстваСертификата Из ТаблицаСвойствСертификатов Цикл
		Отбор.Отпечаток = СвойстваСертификата.Отпечаток;
		Строки = Сертификаты.НайтиСтроки(Отбор);
		Если Строки.Количество() = 0 Тогда
			Если Сертификаты.Количество()-1 < Индекс Тогда
				Строка = Сертификаты.Добавить();
			Иначе
				Строка = Сертификаты.Вставить(Индекс);
			КонецЕсли;
		Иначе
			Строка = Строки[0];
			ИндексСтроки = Сертификаты.Индекс(Строка);
			Если ИндексСтроки <> Индекс Тогда
				Сертификаты.Сдвинуть(ИндексСтроки, Индекс - ИндексСтроки);
			КонецЕсли;
		КонецЕсли;
		// Обновление только измененных значений, чтобы таблица формы не обновлялась лишний раз.
		ОбновитьЗначение(Строка.Отпечаток,            СвойстваСертификата.Отпечаток);
		ОбновитьЗначение(Строка.Представление,        СвойстваСертификата.Представление);
		ОбновитьЗначение(Строка.КемВыдан,             СвойстваСертификата.КемВыдан);
		ОбновитьЗначение(Строка.НаКлиенте,            СвойстваСертификата.НаКлиенте);
		ОбновитьЗначение(Строка.НаСервере,            СвойстваСертификата.НаСервере);
		ОбновитьЗначение(Строка.ЭтоЗаявление,         СвойстваСертификата.ЭтоЗаявление);
		ОбновитьЗначение(Строка.ВОблачномСервисе,     СвойстваСертификата.ВОблачномСервисе);
		ОбновитьЗначение(Строка.ТипРазмещения,        СвойстваСертификата.ТипРазмещения);
		ОбновитьЗначение(Строка.СостояниеСертификата, СвойстваСертификата.СостояниеСертификата);
		ОбновитьЗначение(Строка.ЕстьВСправочнике,     СвойстваСертификата.ЕстьВСправочнике);
		ОбработанныеСтроки.Вставить(Строка, Истина);
		Индекс = Индекс + 1;
	КонецЦикла;
	
	Индекс = Сертификаты.Количество()-1;
	Пока Индекс >=0 Цикл
		Строка = Сертификаты.Получить(Индекс);
		Если ОбработанныеСтроки.Получить(Строка) = Неопределено Тогда
			Сертификаты.Удалить(Индекс);
		КонецЕсли;
		Индекс = Индекс-1;
	КонецЦикла;
	
КонецПроцедуры

// Для функции ПроверитьСертификат
Функция ПроверитьСертификатНаКорректность(МенеджерКриптографииДляПроверки, СертификатДляПроверки, 
	РежимыПроверкиСертификата, ОписаниеОшибки, ВызыватьИсключение)
	
	Попытка
		МенеджерКриптографииДляПроверки.ПроверитьСертификат(СертификатДляПроверки, РежимыПроверкиСертификата);
		Возврат Истина;
	Исключение
		ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;
	
	Если Не ЗначениеЗаполнено(ОписаниеОшибки) Тогда
		Возврат Ложь;
	КонецЕсли;

	ОшибкаПоКлассификатору = ОшибкаПоКлассификатору(ОписаниеОшибки, Истина);
	Если ОшибкаПоКлассификатору = Неопределено Тогда
		Возврат Ложь;
	КонецЕсли;

	Если ОшибкаПоКлассификатору.СертификатОтозван Тогда
		Попытка
			ЗаписатьОтметкуОбОтзывеСертификата(Base64Строка(СертификатДляПроверки.Отпечаток));
		Исключение
			ОписаниеОшибки = ОписаниеОшибки + Символы.ПС + ОбработкаОшибок.КраткоеПредставлениеОшибки(
				ИнформацияОбОшибке());
		КонецПопытки;
		Возврат Ложь;
	КонецЕсли;

	Если ЗначениеЗаполнено(ОшибкаПоКлассификатору.ДействияДляУстранения) Тогда
		Возврат ПроверитьСертификатНаКорректностьПовторно(МенеджерКриптографииДляПроверки, СертификатДляПроверки,
			РежимыПроверкиСертификата, ОписаниеОшибки, ВызыватьИсключение,
			ОшибкаПоКлассификатору.ДействияДляУстранения);
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

// Для функции ПроверитьСертификат
Функция ПроверитьСертификатНаКорректностьПовторно(МенеджерКриптографииДляПроверки, СертификатДляПроверки, 
	РежимыПроверкиСертификата, ОписаниеОшибки, ВызыватьИсключение, ДействияДляУстранения)
	
	// Локализация
	
	ТребуетсяУстановкаСпискаОтзыва = Ложь;
	
	Если ТипЗнч(МенеджерКриптографииДляПроверки) = Тип("МенеджерКриптографии") Тогда
		Если ЗначениеЗаполнено(ДействияДляУстранения) И ДействияДляУстранения.Найти("УстановитьСписокОтзываСертификата") <> Неопределено Тогда
			ИмяИздателя = НРег(ЭлектроннаяПодпись.СвойстваИздателяСертификата(СертификатДляПроверки).ОбщееИмя);
			Если ЗначениеЗаполнено(ИмяИздателя) Тогда
				ИмяИздателя = СтроковыеФункции.СтрокаЛатиницей(ИмяИздателя);
				АдресСпискаОтзываВнутренний = ЭлектроннаяПодписьСлужебныйКлиентСервер.АдресСпискаОтзываВнутренний(
					ИмяИздателя, СертификатДляПроверки.Выгрузить());
				Если ЗначениеЗаполнено(АдресСпискаОтзываВнутренний.АдресВнутренний) Тогда
					ТребуетсяУстановкаСпискаОтзыва = Истина;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Если ТребуетсяУстановкаСпискаОтзыва Тогда
		
		Попытка
			УстановитьСписокОтзываСертификата(СертификатДляПроверки,
				АдресСпискаОтзываВнутренний.АдресВнешний, АдресСпискаОтзываВнутренний.АдресВнутренний);
		Исключение
			
			ЗаписьЖурналаРегистрации(
					НСтр("ru = 'Электронная подпись.Обновление списков отзыва'",
					ОбщегоНазначения.КодОсновногоЯзыка()),
					УровеньЖурналаРегистрации.Ошибка, , ,
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			
			Возврат Ложь;
		КонецПопытки;
		
		// Повторная проверка после установки списка отзыва.
		Попытка
			МенеджерКриптографииДляПроверки.ПроверитьСертификат(СертификатДляПроверки, РежимыПроверкиСертификата);
		Исключение

			ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());

			Если ВызыватьИсключение Тогда
				ВызватьИсключение;
			КонецЕсли;
			Возврат Ложь;
		КонецПопытки;
		
		Возврат Истина;
		
	КонецЕсли;
	
	// Конец Локализация
	
	Возврат Ложь;
	
КонецФункции

// Только для внутреннего использования.
//
// Параметры:
//   Контекст - Структура:
//     * ОшибкаНаСервере - Структура:
//         ** Ошибки - Массив
//
Функция ЗаписатьСертификатПослеПроверки(Контекст) Экспорт
	
	ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
	ПараметрыСоздания.ОписаниеОшибки = Новый Структура;
	ПараметрыСоздания.АлгоритмПодписи = Контекст.АлгоритмПодписи;
	
	МенеджерКриптографии = МенеджерКриптографии("", ПараметрыСоздания);
	
	Контекст.Вставить("ОшибкаНаСервере",
		ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок());
	
	ЗаголовокОшибкиПрограммы = ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаголовокОшибкиДобавленияСертификата(
			?(Контекст.ДляШифрования = Истина, "Шифрование", "Подписание"), ИмяКомпьютера());
	
	Если ТипЗнч(МенеджерКриптографии) <> Тип("МенеджерКриптографии")
		И ПараметрыСоздания.ОписаниеОшибки.Общая Тогда
		
		Контекст.ОшибкаНаСервере = ПараметрыСоздания.ОписаниеОшибки;
		Контекст.ОшибкаНаСервере.ЗаголовокОшибки = ЗаголовокОшибкиПрограммы;
		Возврат Неопределено;
	КонецЕсли;
	
	ОписанияПрограмм = ЭлектроннаяПодпись.ОбщиеНастройки().ОписанияПрограмм;
	ПрограммаПоСертификатуРезультат = ПрограммаПоСертификату(
		Контекст.ДанныеСертификата, Истина);
	
	Если ЗначениеЗаполнено(ПрограммаПоСертификатуРезультат.Программа) Тогда
		ОписанияПрограмм = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииОписанияПрограмм(
			ПрограммаПоСертификатуРезультат.Программа, Контекст.ОшибкаНаСервере.Ошибки, ОписанияПрограмм);
	Иначе
		
		ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииДобавитьОшибку(
			Контекст.ОшибкаНаСервере.Ошибки, Неопределено, ПрограммаПоСертификатуРезультат.Ошибка, Истина);
		
	КонецЕсли;
	
	СертификатКриптографии = Новый СертификатКриптографии(Контекст.ДанныеСертификата);
	ЭтоПолноправныйПользователь = Пользователи.ЭтоПолноправныйПользователь(,, Ложь);
	
	Для Каждого ОписаниеПрограммы Из ОписанияПрограмм Цикл
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.Программа = ОписаниеПрограммы.Ссылка;
		ПараметрыСоздания.ОписаниеОшибки = Новый Структура;
		ПараметрыСоздания.АлгоритмПодписи = Контекст.АлгоритмПодписи;
		
		МенеджерКриптографии = МенеджерКриптографии("", ПараметрыСоздания);
		
		Если МенеджерКриптографии = Неопределено Тогда
			Ошибки = ПараметрыСоздания.ОписаниеОшибки.Ошибки;
			
			Если Ошибки.Количество() > 0
			   И Не (ЗначениеЗаполнено(Контекст.АлгоритмПодписи)
			         И Ошибки[0].НетАлгоритма) Тогда
				
				Ошибки[0].ЗаголовокОшибки = ЗаголовокОшибкиПрограммы;
				Контекст.ОшибкаНаСервере.Ошибки.Добавить(Ошибки[0]);
			КонецЕсли;
			
			Продолжить;
			
		КонецЕсли;
		
		МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу = Контекст.ПарольСертификата;
		
		Если Контекст.ДляШифрования = Истина Тогда
			Успех = ПроверитьШифрованиеИРасшифровку(МенеджерКриптографии, Контекст.ДанныеСертификата,
				СертификатКриптографии, ОписаниеПрограммы, Контекст.ОшибкаНаСервере, ЭтоПолноправныйПользователь);
		Иначе
			Успех = ПроверитьПодписание(МенеджерКриптографии, Контекст.ДанныеСертификата,
				СертификатКриптографии, ОписаниеПрограммы, Контекст.ОшибкаНаСервере, ЭтоПолноправныйПользователь);
		КонецЕсли;
		
		Если Не Успех Тогда
			Продолжить;
		КонецЕсли;
		
		Контекст.Вставить("ОписаниеПрограммы", ОписаниеПрограммы);
		Возврат ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаписатьСертификатВСправочник(Контекст,
			Контекст.ОшибкаНаСервере);
		
	КонецЦикла;
	
	Возврат Неопределено;
	
КонецФункции

// Только для внутреннего использования.
// 
// Параметры:
//  Отпечаток - Строка - отпечаток сертификата в формате Base64Строка 
//
Функция ЗаписатьОтметкуОбОтзывеСертификата(Отпечаток) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Отпечаток", Отпечаток);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Сертификаты.Ссылка КАК Ссылка
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
	|ГДЕ
	|	Сертификаты.Отпечаток = &Отпечаток
	|	И НЕ Сертификаты.Отозван";
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если РезультатЗапроса.Пустой() Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Выборка = РезультатЗапроса.Выбрать();
	Выборка.Следующий();
	СсылкаНаСертификат = Выборка.Ссылка;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования");
	ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаСертификат);
	
	НачатьТранзакцию();
	Попытка
		
		Блокировка.Заблокировать();
		СертификатОбъект = СсылкаНаСертификат.ПолучитьОбъект();
		
		Если СертификатОбъект.Отозван <> Истина Тогда
			СертификатОбъект.Отозван = Истина;
			СертификатОбъект.ОбменДанными.Загрузка = Истина;
			СертификатОбъект.Записать();
		КонецЕсли;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось записать отметку об отзыве сертификата %1: %2'"), СсылкаНаСертификат, 
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
		
		ЗаписьЖурналаРегистрации(
			НСтр("ru = 'Электронная подпись.Установка отметки об отзыве сертификата.'",
			ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка, , СсылкаНаСертификат,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Возврат СсылкаНаСертификат;
	
КонецФункции

// Только для внутреннего использования.
Функция ВстроенныйКриптопровайдер() Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ ПЕРВЫЕ 1
	|	Программы.Ссылка КАК Ссылка
	|ИЗ
	|	Справочник.ПрограммыЭлектроннойПодписиИШифрования КАК Программы
	|ГДЕ
	|	Программы.ЭтоВстроенныйКриптопровайдер
	|	И НЕ Программы.ПометкаУдаления
	|
	|УПОРЯДОЧИТЬ ПО
	|	Программы.Наименование";
	
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		ВстроенныйКриптопровайдер = Выборка.Ссылка;
	Иначе
		ВстроенныйКриптопровайдер = Неопределено;
	КонецЕсли;
	
	Возврат ВстроенныйКриптопровайдер;
	
КонецФункции

// Только для внутреннего использования.
Функция ОблачныйПарольПодтвержден(Сертификат)
	
	Если Не ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если ТипЗнч(Сертификат) = Тип("ДвоичныеДанные") Тогда
		ДанныеСертификата = Сертификат;
		
	ИначеЕсли ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда
		ДанныеСертификата = Сертификат.Выгрузить();
	Иначе
		ДанныеСертификата = ПолучитьИзВременногоХранилища(Сертификат);
	КонецЕсли;
	
	МодульСервисКриптографии = ОбщегоНазначения.ОбщийМодуль("СервисКриптографии");
	СвойстваСертификата = МодульСервисКриптографии.ПолучитьСвойстваСертификата(ДанныеСертификата);
	
	МаркерыБезопасности = МаркерыБезопасности(СвойстваСертификата.Идентификатор);
	
	Возврат ЗначениеЗаполнено(МаркерыБезопасности.МаркерБезопасности);
	
КонецФункции

// Для функции ОблачныйПарольПодтвержден.
Функция МаркерыБезопасности(ИдентификаторСертификата)

	Результат = Новый Структура();
	Результат.Вставить("МаркерБезопасности");
	
	УстановитьПривилегированныйРежим(Истина);
	Результат.МаркерБезопасности = ПараметрыСеанса["МаркерыБезопасности"].Получить(ИдентификаторСертификата);
	
	УстановитьПривилегированныйРежим(Ложь);
	
	// Незаполненные значения заменим пустыми строками для передачи в сервис криптографии.
	Если Не ЗначениеЗаполнено(Результат.МаркерБезопасности) Тогда
		Результат.МаркерБезопасности = "";
	КонецЕсли;
	
	Возврат Результат;

КонецФункции

// В ОС Linux и MacOS при создании менеджера криптографии
// требуется указывать путь к программе.
//
// Возвращаемое значение:
//  Булево
//
Функция ТребуетсяПутьКПрограмме(НаКлиенте = Ложь) Экспорт
	
	Если НаКлиенте Тогда
		Возврат ОбщегоНазначения.ЭтоLinuxКлиент()
		    Или ОбщегоНазначения.ЭтоMacOSКлиент();
	КонецЕсли;
	
	СистемнаяИнформация = Новый СистемнаяИнформация;
	
	Возврат ОбщегоНазначения.ЭтоLinuxСервер()
		Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.MacOS_x86
		Или СистемнаяИнформация.ТипПлатформы = ТипПлатформы.MacOS_x86_64;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Общие процедуры и функции управляемых форм.

// Только для внутреннего использования.
// 
// Параметры:
//  СписокСертификатов - СписокЗначений - список сертификатов, в который нужно добавить сертификаты из личного хранилища.
//  Ошибка - Строка - ошибка
//
Процедура ДополнитьСписокСертификатовВЛичномХранилищеНаСервере(СписокСертификатов, Ошибка = "") Экспорт
	
	Если ЭлектроннаяПодпись.СоздаватьЭлектронныеПодписиНаСервере() Тогда

		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ОписаниеОшибки = Ошибка;
		
		МенеджерКриптографии = МенеджерКриптографии("ПолучениеСертификатов", ПараметрыСоздания);
		
		Ошибка = ПараметрыСоздания.ОписаниеОшибки;
		Если МенеджерКриптографии <> Неопределено Тогда
			
			Попытка
				МассивСертификатов = МенеджерКриптографии.ПолучитьХранилищеСертификатов(
					ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты).ПолучитьВсе();
				Для Каждого Элемент Из МассивСертификатов Цикл
					СписокСертификатов.Добавить(Base64Строка(Элемент.Отпечаток));
				КонецЦикла;
			Исключение
				ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
				Если ТипЗнч(Ошибка) = Тип("Структура") Тогда
					Ошибка = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовоеОписаниеОшибок(ИмяКомпьютера());
					Ошибка.ОписаниеОшибки = ОписаниеОшибки;
				Иначе
					Ошибка = ОписаниеОшибки;
				КонецЕсли;
			КонецПопытки;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
		
		МодульХранилищеСертификатов = ОбщегоНазначения.ОбщийМодуль("ХранилищеСертификатов");
		МассивСертификатов = МодульХранилищеСертификатов.Получить("ПерсональныеСертификаты");
		Для Каждого Элемент Из МассивСертификатов Цикл
			СписокСертификатов.Добавить(Base64Строка(Элемент.Отпечаток));
		КонецЦикла;
		
	КонецЕсли;
	
	Если ИспользоватьСервисОблачнойПодписи() Тогда
		МодульСервисКриптографииDSSСлужебный = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSSСлужебный");
		МассивСертификатов = МодульСервисКриптографииDSSСлужебный.ПолучитьДанныеСертификатов(Ложь);
		Для Каждого Элемент Из МассивСертификатов Цикл
			СписокСертификатов.Добавить(Base64Строка(Элемент.Отпечаток));
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура НастроитьФормуПодписанияШифрованияРасшифровки(Форма, Шифрование = Ложь, Расшифровка = Ложь) Экспорт
	
	Элементы  = Форма.Элементы;
	Параметры = Форма.Параметры;
	
	Элементы.Сертификат.КнопкаВыпадающегоСписка = Истина;
	Элементы.Сертификат.ОтображениеКнопкиВыбора = ОтображениеКнопкиВыбора.ОтображатьВВыпадающемСписке;
	
	Форма.Заголовок = Параметры.Операция;
	Форма.ВыполнятьНаСервере = Параметры.ВыполнятьНаСервере;
	
	Если Шифрование Тогда
		Если Форма.УказанНеизменяемыйНаборСертификатов Тогда
			Форма.БезПодтверждения = Параметры.БезПодтверждения;
		КонецЕсли;
	Иначе
		Форма.ОтборСертификатов = Новый СписокЗначений;
		Если ТипЗнч(Параметры.ОтборСертификатов) = Тип("Массив") Тогда
			Форма.ОтборСертификатов.ЗагрузитьЗначения(Параметры.ОтборСертификатов);
		ИначеЕсли ТипЗнч(Параметры.ОтборСертификатов) = Тип("Структура") Тогда
			Форма.ОтборСертификатов = Параметры.ОтборСертификатов.Организация;
		КонецЕсли;
		Форма.БезПодтверждения = Параметры.БезПодтверждения;
	КонецЕсли;
	
	ЭлементПредставлениеДанных = Элементы.ПредставлениеДанных; // ПолеФормы, РасширениеПоляФормыДляПоляНадписи
	Если ЗначениеЗаполнено(Параметры.ЗаголовокДанных) Тогда
		ЭлементПредставлениеДанных.Заголовок = Параметры.ЗаголовокДанных;
	Иначе
		ЭлементПредставлениеДанных.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
	КонецЕсли;
	
	Форма.ПредставлениеДанных = Параметры.ПредставлениеДанных;
	ЭлементПредставлениеДанных.Гиперссылка = Параметры.ПредставлениеДанныхОткрывается;
	
	Если Не ЗначениеЗаполнено(Форма.ПредставлениеДанных) Тогда
		ЭлементПредставлениеДанных.Видимость = Ложь;
	КонецЕсли;
	
	Если Расшифровка Тогда
		ЗаполнитьОтборОтпечатков(Форма);
	ИначеЕсли Не Шифрование Тогда // Подписание
		Элементы.Комментарий.Видимость = Параметры.ПоказатьКомментарий И Не Форма.БезПодтверждения;
	КонецЕсли;
	
	Если Не Шифрование Тогда
		ЗаполнитьСуществующиеСертификатыПользователя(Форма.СертификатСписокВыбора,
			Параметры.ОтпечаткиСертификатовНаКлиенте, Форма.ОтборСертификатов,
			Форма.ОтборОтпечатков, Расшифровка, Форма.ВыполнятьНаСервере);
	КонецЕсли;
	
	Сертификат = Неопределено;
	
	Если Расшифровка Тогда
		Для каждого ЭлементСписка Из Форма.СертификатСписокВыбора Цикл
			Если ТипЗнч(ЭлементСписка.Значение) = Тип("Строка") Тогда
				Продолжить;
			КонецЕсли;
			Сертификат = ЭлементСписка.Значение;
			Прервать;
		КонецЦикла;
		
	ИначеЕсли ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
		Если Шифрование Тогда
			Сертификат = ХранилищеОбщихНастроек.Загрузить("Криптография", "СертификатДляШифрования");
		Иначе
			Сертификат = ХранилищеОбщихНастроек.Загрузить("Криптография", "СертификатДляПодписания");
		КонецЕсли;
	КонецЕсли;
	
	Если Не Шифрование И ТипЗнч(Форма.ОтборСертификатов) = Тип("СписокЗначений") Тогда
		Если Форма.СертификатСписокВыбора.Количество() = 0 Тогда
			Сертификат = Неопределено;
		Иначе
			Сертификат = Форма.СертификатСписокВыбора[0].Значение;
		КонецЕсли;
	КонецЕсли;
	
	Если Не (Шифрование И Форма.УказанНеизменяемыйНаборСертификатов) Тогда
		Форма.Сертификат = Сертификат;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Форма.Сертификат)
	   И ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Форма.Сертификат, "Ссылка") <> Форма.Сертификат Тогда
		
		Форма.Сертификат = Неопределено;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Форма.Сертификат) Тогда
		Если Шифрование Тогда
			Форма.ИмяПоляАктивизироватьПоУмолчанию = "СертификатыШифрования";
		Иначе
			Форма.ИмяПоляАктивизироватьПоУмолчанию = "Пароль";
		КонецЕсли;
	Иначе
		Если Не (Шифрование И Форма.УказанНеизменяемыйНаборСертификатов) Тогда
			Форма.ИмяПоляАктивизироватьПоУмолчанию = "Сертификат";
		КонецЕсли;
	КонецЕсли;
	
	ЗаполнитьДополнительныеСвойстваСертификата(Форма);
	
	Форма.МенеджерКриптографииНаСервереОписаниеОшибки = Новый Структура;
	Если ЭлектроннаяПодпись.СоздаватьЭлектронныеПодписиНаСервере() Тогда
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ОписаниеОшибки = Новый Структура;
		
		МенеджерКриптографии("ПолучениеСертификатов", ПараметрыСоздания);
		Форма.МенеджерКриптографииНаСервереОписаниеОшибки = ПараметрыСоздания.ОписаниеОшибки;
		
	КонецЕсли;
	
	Если Не Шифрование Тогда
		ЭлектроннаяПодписьПереопределяемый.ПередНачаломОперации(?(Расшифровка, "Расшифровка", "Подписание"),
			Параметры.ПараметрыДополнительныхДействий, Форма.ВыходныеПараметрыДополнительныхДействий);
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура СертификатПриИзмененииНаСервере(Форма, ОтпечаткиСертификатовНаКлиенте, Шифрование = Ложь, Расшифровка = Ложь) Экспорт
	
	Если (ТипЗнч(Форма.ОтборСертификатов) <> Тип("СписокЗначений")
		Или ТипЗнч(Форма.ОтборСертификатов) = Тип("СписокЗначений") И Форма.ОтборСертификатов.Количество() = 0)
		И ПравоДоступа("СохранениеДанныхПользователя", Метаданные) Тогда
		
		Если Шифрование Тогда
			ХранилищеОбщихНастроек.Сохранить("Криптография", "СертификатДляШифрования", Форма.Сертификат);
		ИначеЕсли Не Расшифровка Тогда
			ХранилищеОбщихНастроек.Сохранить("Криптография", "СертификатДляПодписания", Форма.Сертификат);
		КонецЕсли;
		
	КонецЕсли;
	
	ЗаполнитьСуществующиеСертификатыПользователя(Форма.СертификатСписокВыбора,
		ОтпечаткиСертификатовНаКлиенте, Форма.ОтборСертификатов,
		Форма.ОтборОтпечатков, Расшифровка, Форма.ВыполнятьНаСервере);
	
	ЗаполнитьДополнительныеСвойстваСертификата(Форма);
	
КонецПроцедуры

// Только для внутреннего использования.
Функция СохраненныеСвойстваСертификата(Отпечаток, Адрес, ПараметрыРеквизитов, ДляШифрования = Ложь) Экспорт
	
	СохраненныеСвойства = Новый Структура;
	СохраненныеСвойства.Вставить("Ссылка");
	СохраненныеСвойства.Вставить("Наименование");
	СохраненныеСвойства.Вставить("Пользователь");
	СохраненныеСвойства.Вставить("Организация");
	СохраненныеСвойства.Вставить("ВводитьПарольВПрограммеЭлектроннойПодписи");
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Отпечаток", Отпечаток);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Сертификаты.Ссылка КАК Ссылка,
	|	Сертификаты.Наименование КАК Наименование,
	|	Сертификаты.Пользователь,
	|	Сертификаты.Организация,
	|	Сертификаты.ВводитьПарольВПрограммеЭлектроннойПодписи,
	|	Сертификаты.ДанныеСертификата
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
	|ГДЕ
	|	Сертификаты.Отпечаток = &Отпечаток";
	
	СертификатКриптографии = Новый СертификатКриптографии(ПолучитьИзВременногоХранилища(Адрес));
	
	ЗначенияЗаполнения = ПараметрыРеквизитов;
	ПараметрыРеквизитов = Неопределено; // Заполняется в процедуре ПередНачаломРедактированияСертификатаКлюча.
	
	Выборка = Запрос.Выполнить().Выбрать();
	Если Выборка.Следующий() Тогда
		ЗаполнитьЗначенияСвойств(СохраненныеСвойства, Выборка);
	Иначе
		СохраненныеСвойства.Ссылка = Справочники.СертификатыКлючейЭлектроннойПодписиИШифрования.ПустаяСсылка();
		
		Если ТипЗнч(ЗначенияЗаполнения) = Тип("Структура")
		   И ЗначенияЗаполнения.Свойство("Организация")
		   И ЗначениеЗаполнено(ЗначенияЗаполнения.Организация) Тогда
			
			СохраненныеСвойства.Организация = ЗначенияЗаполнения.Организация;
			
		ИначеЕсли Не Метаданные.ОпределяемыеТипы.Организация.Тип.СодержитТип(Тип("Строка")) Тогда
			ПолноеИмя = Метаданные.НайтиПоТипу(Метаданные.ОпределяемыеТипы.Организация.Тип.Типы()[0]).ПолноеИмя();
			ИмяСправочникаОрганизации = "Справочники." + СтрРазделить(ПолноеИмя, ".")[1];
			МодульОрганизации = ОбщегоНазначения.ОбщийМодуль(ИмяСправочникаОрганизации);
			Если Не ДляШифрования Тогда
				СохраненныеСвойства.Организация = МодульОрганизации.ОрганизацияПоУмолчанию();
			КонецЕсли;
		КонецЕсли;
		
		СвойстваСертификата = ЭлектроннаяПодпись.СвойстваСертификата(СертификатКриптографии);
		СохраненныеСвойства.Наименование = СвойстваСертификата.Представление;
		
		Если Не ДляШифрования Тогда
			СохраненныеСвойства.Пользователь = Пользователи.ТекущийПользователь();
		КонецЕсли;
	КонецЕсли;
	
	ПередНачаломРедактированияСертификатаКлюча(
		СохраненныеСвойства.Ссылка, СертификатКриптографии, ПараметрыРеквизитов);
	
	Если Не ЗначениеЗаполнено(СохраненныеСвойства.Ссылка) Тогда
		ЗаполнитьРеквизит(СохраненныеСвойства, ПараметрыРеквизитов, "Наименование");
		ЗаполнитьРеквизит(СохраненныеСвойства, ПараметрыРеквизитов, "Пользователь");
		ЗаполнитьРеквизит(СохраненныеСвойства, ПараметрыРеквизитов, "Организация");
		ЗаполнитьРеквизит(СохраненныеСвойства, ПараметрыРеквизитов, "ВводитьПарольВПрограммеЭлектроннойПодписи");
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(СохраненныеСвойства.Ссылка)
	   И ТипЗнч(ЗначенияЗаполнения) = Тип("Структура")
	   И ЗначенияЗаполнения.Свойство("Организация")
	   И ЗначениеЗаполнено(ЗначенияЗаполнения.Организация)
	   И Не ПараметрыРеквизитов.Свойство("Организация") Тогда
	
		Параметры = Новый Структура;
		Параметры.Вставить("ТолькоПросмотр",     Истина);
		Параметры.Вставить("ПроверкаЗаполнения", Ложь);
		Параметры.Вставить("Видимость",          Истина);
		ПараметрыРеквизитов.Вставить("Организация", Параметры);
	КонецЕсли;
	
	Возврат СохраненныеСвойства;
	
КонецФункции

// Только для внутреннего использования.
// 
// Параметры:
//  Форма - ФормаКлиентскогоПриложения:
//    * СертификатПараметрыРеквизитов - см. НовыеПараметрыРеквизитовСертификата
//  Программа - Неопределено
//  ДляШифрования - Булево
//
Процедура ЗаписатьСертификатВСправочник(Форма, Программа = Неопределено, ДляШифрования = Ложь) Экспорт
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("Наименование",   Форма.СертификатНаименование);
	ДополнительныеПараметры.Вставить("Пользователь",   Форма.СертификатПользователь);
	ДополнительныеПараметры.Вставить("Организация",    Форма.СертификатОрганизация);
	ДополнительныеПараметры.Вставить("ФизическоеЛицо", Форма.СертификатФизическоеЛицо);
	
	Если Не ДляШифрования Тогда
		ДополнительныеПараметры.Вставить("Программа", Программа);
		ДополнительныеПараметры.Вставить("ВводитьПарольВПрограммеЭлектроннойПодписи",
			Форма.СертификатВводитьПарольВПрограммеЭлектроннойПодписи);
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Форма.Сертификат) Тогда
		ПропускаемыеРеквизиты = Новый Соответствие;
		ПропускаемыеРеквизиты.Вставить("Ссылка",         Истина);
		ПропускаемыеРеквизиты.Вставить("Наименование",   Истина);
		ПропускаемыеРеквизиты.Вставить("Организация",    Истина);
		ПропускаемыеРеквизиты.Вставить("ФизическоеЛицо", Истина);
		ПропускаемыеРеквизиты.Вставить("ВводитьПарольВПрограммеЭлектроннойПодписи", Истина);
		Если Не ДляШифрования И Форма.ЛичныйСписокПриДобавлении Тогда
			ПропускаемыеРеквизиты.Вставить("Пользователь",  Истина);
		КонецЕсли;
		Для каждого КлючИЗначение Из Форма.СертификатПараметрыРеквизитов Цикл
			ИмяРеквизита = КлючИЗначение.Ключ;
			Свойства     = КлючИЗначение.Значение; // см. НовыеПараметрыРеквизитаСертификата
			Если ПропускаемыеРеквизиты.Получить(ИмяРеквизита) <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			Если Свойства.ЗначениеЗаполнения = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ДополнительныеПараметры.Вставить(ИмяРеквизита, Свойства.ЗначениеЗаполнения);
		КонецЦикла;
	КонецЕсли;
	
	Форма.Сертификат = ЭлектроннаяПодпись.ЗаписатьСертификатВСправочник(Форма.СертификатАдрес,
		ДополнительныеПараметры);
	
КонецПроцедуры

// Только для внутреннего использования.
//
// Параметры:
//   Список - ДинамическийСписок
//
Процедура УстановитьУсловноеОформлениеСпискаСертификатов(Список, ИсключитьЗаявления = Ложь) Экспорт
	
	ЭлементУсловногоОформления = Список.УсловноеОформление.Элементы.Добавить();
	
	ЭлементЦветаОформления = ЭлементУсловногоОформления.Оформление.Элементы.Найти("TextColor");
	ЭлементЦветаОформления.Значение = Метаданные.ЭлементыСтиля.ТекстЗапрещеннойЯчейкиЦвет.Значение;
	ЭлементЦветаОформления.Использование = Истина;
	
	Если ИсключитьЗаявления И Метаданные.Обработки.Найти("ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата") <> Неопределено Тогда
		ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата =
			ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(
				"Обработка.ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата");
		ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата.УстановитьУсловноеОформлениеСпискаСертификатов(
			ЭлементУсловногоОформления);
	КонецЕсли;
	
	ГруппаЭлементовОтбора = ЭлементУсловногоОформления.Отбор.Элементы.Добавить(Тип("ГруппаЭлементовОтбораКомпоновкиДанных"));
	ГруппаЭлементовОтбора.ТипГруппы = ТипГруппыЭлементовОтбораКомпоновкиДанных.ГруппаНе;
	
	ЭлементОтбораДанных = ГруппаЭлементовОтбора.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбораДанных.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных("Отозван");
	ЭлементОтбораДанных.ВидСравнения   = ВидСравненияКомпоновкиДанных.Равно;
	ЭлементОтбораДанных.ПравоеЗначение = Ложь;
	ЭлементОтбораДанных.Использование  = Истина;
	
	ЭлементОтбораДанных = ГруппаЭлементовОтбора.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбораДанных.ЛевоеЗначение  = Новый ПолеКомпоновкиДанных("ДействителенДо");
	ЭлементОтбораДанных.ВидСравнения   = ВидСравненияКомпоновкиДанных.Больше;
	ЭлементОтбораДанных.ПравоеЗначение = Новый СтандартнаяДатаНачала(ВариантСтандартнойДатыНачала.НачалоЭтогоДня);
	ЭлементОтбораДанных.Использование  = Истина;
	
	ЭлементОформляемогоПоля = ЭлементУсловногоОформления.Поля.Элементы.Добавить();
	ЭлементОформляемогоПоля.Поле = Новый ПолеКомпоновкиДанных("");
	ЭлементОформляемогоПоля.Использование = Истина;
	
КонецПроцедуры

// Только для внутреннего использования.
//
// Параметры:
//   ДанныеСертификата - ДвоичныеДанные
//
Функция СертификатИзДвоичныхДанных(ДанныеСертификата) Экспорт
	
	Если ТипЗнч(ДанныеСертификата) <> Тип("ДвоичныеДанные") Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Попытка
		СертификатКриптографии = Новый СертификатКриптографии(ДанныеСертификата);
	Исключение
		СертификатКриптографии = Неопределено;
	КонецПопытки;
	
	Если СертификатКриптографии <> Неопределено Тогда
		Возврат СертификатКриптографии;
	КонецЕсли;
	
	ПолноеИмяВременногоФайла = ПолучитьИмяВременногоФайла("cer");
	ДанныеСертификата.Записать(ПолноеИмяВременногоФайла);
	Текст = Новый ТекстовыйДокумент;
	Текст.Прочитать(ПолноеИмяВременногоФайла);
	
	Попытка
		УдалитьФайлы(ПолноеИмяВременногоФайла);
	Исключение
		ЗаписьЖурналаРегистрации(
			НСтр("ru = 'Электронная подпись.Удаление временного файла'",
				ОбщегоНазначения.КодОсновногоЯзыка()),
			УровеньЖурналаРегистрации.Ошибка, , ,
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
	КонецПопытки;
	
	Если СтрНачинаетсяС(Текст.ПолучитьСтроку(1), "MII") Тогда
		СтрокаBase64 = Текст.ПолучитьТекст();
	Иначе
		Если Текст.КоличествоСтрок() < 3
			Или Текст.ПолучитьСтроку(1) <> "-----BEGIN CERTIFICATE-----"
			Или Текст.ПолучитьСтроку(Текст.КоличествоСтрок()) <> "-----END CERTIFICATE-----" Тогда
			
			Возврат Неопределено;
		КонецЕсли;
		
		Текст.УдалитьСтроку(1);
		Текст.УдалитьСтроку(Текст.КоличествоСтрок());
		СтрокаBase64 = Текст.ПолучитьТекст();
	КонецЕсли;
	
	Попытка
		ДанныеСертификата = Base64Значение(СтрокаBase64);
	Исключение
		Возврат Неопределено;
	КонецПопытки;
	
	Если ТипЗнч(ДанныеСертификата) <> Тип("ДвоичныеДанные") Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Попытка
		СертификатКриптографии = Новый СертификатКриптографии(ДанныеСертификата);
	Исключение
		СертификатКриптографии = Неопределено;
	КонецПопытки;
	
	Возврат СертификатКриптографии;
	
КонецФункции

// Только для внутреннего использования.
//
// Параметры:
//   Форма - ФормаКлиентскогоПриложения
//
Процедура НастроитьПояснениеВводаПароля(Форма, ИмяЭлементаВводитьПарольВПрограммеЭлектроннойПодписи = "", ИмяЭлементаПояснениеУсиленногоПароля = "") Экспорт
	
	Если ЗначениеЗаполнено(ИмяЭлементаВводитьПарольВПрограммеЭлектроннойПодписи) Тогда
		Элемент = Форма.Элементы[ИмяЭлементаВводитьПарольВПрограммеЭлектроннойПодписи]; // ПолеФормы
		Элемент.Заголовок = НСтр("ru = 'Вводить пароль в программе электронной подписи'");
		Элемент.Подсказка =
			НСтр("ru = '- Включается интерактивный режим работы программы электронной подписи,
			           |  при котором она запрашивает пароль и позволяет его сохранить.
			           |- Отключается запрос пароля в форме 1С:Предприятия.
			           |
			           |Обязательно для закрытых ключей сертификатов, для которых в ОС включена усиленная защита.'");
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ИмяЭлементаПояснениеУсиленногоПароля) Тогда
		Элемент = Форма.Элементы[ИмяЭлементаПояснениеУсиленногоПароля];
		Элемент.Подсказка =
			НСтр("ru = 'Для выбранного сертификата указано ""Вводить пароль в программе электронной подписи"".'");
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//  Форма - ФормаКлиентскогоПриложения
//  Заголовок - Строка
//
Процедура УстановитьЗаголовокОшибки(Форма, Заголовок) Экспорт
	
	Форма.Заголовок = Заголовок;
	
	ШиринаЗаголовка = СтрДлина(Форма.Заголовок);
	Если ШиринаЗаголовка > 80 Тогда
		ШиринаЗаголовка = 80;
	КонецЕсли;
	Если ШиринаЗаголовка > Форма.Ширина Тогда
		Форма.Ширина = ШиринаЗаголовка;
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ВыполнитьОбработкуДанныхРегламентнымЗаданием(ПараметрыЗапроса, ПараметрыВыполнения) Экспорт

	Запрос = ЗапросДляПродленияДостоверностиПодписей(ПараметрыЗапроса);

	Если Запрос = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	Пока Истина Цикл
		УстановитьПривилегированныйРежим(Истина);
		РезультатЗапроса = Запрос.Выполнить();
		УстановитьПривилегированныйРежим(Ложь);
		Если РезультатЗапроса.Пустой() Тогда
			Прервать;
		КонецЕсли;
		Выборка = РезультатЗапроса.Выбрать();
		УсовершенствоватьРегламентнымЗаданием(Выборка, ПараметрыВыполнения);
	КонецЦикла;
		
КонецПроцедуры

// Только для внутреннего использования.
Процедура УсовершенствоватьРегламентнымЗаданием(Выборка, ПараметрыВыполнения)
	
	ТипПодписи = ПараметрыВыполнения.ТипПодписи;
	ДобавитьАрхивнуюМеткуВремени = ПараметрыВыполнения.ТребуетсяДобавитьАрхивныеМетки;
	
	Пока Выборка.Следующий() Цикл
		
		Подпись = Выборка.Подпись.Получить();
		
		Если ПараметрыВыполнения.СлужебнаяУчетнаяЗаписьDSS = Неопределено Тогда
			
			ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
			ПараметрыСоздания.АлгоритмПодписи =
				ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(Подпись);
			МенеджерКриптографии = МенеджерКриптографии(
				"ПродлениеСрокаДействияПодписи", ПараметрыСоздания);
			
			Если МенеджерКриптографии = Неопределено Тогда
				СвойстваПодписи = Новый Структура("ПодписанныйОбъект, ПорядковыйНомер",
					Выборка.ПодписанныйОбъект, Выборка.ПорядковыйНомер);
				ЗарегистрироватьОшибкуУсовершенствованияПодписиВЖурнале(ПараметрыСоздания.ОписаниеОшибки, СвойстваПодписи);
				ВызватьИсключение ПараметрыСоздания.ОписаниеОшибки;
			КонецЕсли;
			
			МенеджерКриптографии.АдресаСерверовМетокВремени = ПараметрыВыполнения.АдресаСерверовМетокВремени;
			
			Результат = ЭлектроннаяПодпись.УсовершенствоватьПодпись(
				Подпись, ТипПодписи, ДобавитьАрхивнуюМеткуВремени, МенеджерКриптографии);
				
		Иначе
			Результат = УсовершенствоватьПодписьВСервисе(Подпись, ПараметрыВыполнения);
		КонецЕсли;
		
		СвойстваПодписи = Результат.СвойстваПодписи;
			
		Если Не Результат.Успех Тогда
			Если СвойстваПодписи = Неопределено Тогда
				СвойстваПодписи = ЭлектроннаяПодписьКлиентСервер.НовыеСвойстваПодписи();
			КонецЕсли;
			СвойстваПодписи.ПодписанныйОбъект = Выборка.ПодписанныйОбъект;
			СвойстваПодписи.ПорядковыйНомер = Выборка.ПорядковыйНомер;
			СвойстваПодписи.ОшибкаПриАвтоматическомПродлении = Истина;
			
			ЗарегистрироватьОшибкуУсовершенствованияПодписиВЖурнале(Результат.ТекстОшибки, СвойстваПодписи);
			
			ПредставлениеОшибки = ОбновитьУсовершенствованнуюПодпись(СвойстваПодписи);
			Если Не ПустаяСтрока(ПредставлениеОшибки) Тогда
				ВызватьИсключение ПредставлениеОшибки;
			КонецЕсли;
			Продолжить;
		КонецЕсли;
		
		СвойстваПодписи.ПодписанныйОбъект = Выборка.ПодписанныйОбъект;
		СвойстваПодписи.ПорядковыйНомер = Выборка.ПорядковыйНомер;
		ПредставлениеОшибки = ОбновитьУсовершенствованнуюПодпись(СвойстваПодписи);
		Если Не ПустаяСтрока(ПредставлениеОшибки) Тогда
			ВызватьИсключение ПредставлениеОшибки;
		КонецЕсли;
		
		Если ЗначениеЗаполнено(СвойстваПодписи.Подпись) Тогда
			ЗарегистрироватьУсовершенствованиеПодписиВЖурнале(СвойстваПодписи);
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Только для внутреннего использования.
Процедура ЗарегистрироватьУсовершенствованиеПодписиВЖурнале(СвойстваПодписи) Экспорт
	
	ПодписанныйОбъект = СвойстваПодписи.ПодписанныйОбъект;
	ПодписанныйОбъектМетаданные = ПодписанныйОбъект.Метаданные();
	
	ИмяСобытия = НСтр("ru = 'Электронная подпись.УсовершенствованиеПодписи'",
		ОбщегоНазначения.КодОсновногоЯзыка());
		
	СообщениеЖурналаРегистрации = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Порядковый номер подписи %1, тип подписи %2, срок действия %3'"), 
		СвойстваПодписи.ПорядковыйНомер, СвойстваПодписи.ТипПодписи, СвойстваПодписи.СрокДействияПоследнейМеткиВремени);
	
	ЗаписьЖурналаРегистрации(ИмяСобытия,
		УровеньЖурналаРегистрации.Информация,
		ПодписанныйОбъектМетаданные,
		ПодписанныйОбъект,
		СообщениеЖурналаРегистрации);
	
КонецПроцедуры 
	
// Только для внутреннего использования.
Процедура ЗарегистрироватьОшибкуУсовершенствованияПодписиВЖурнале(ОписаниеОшибки, СвойстваПодписи = Неопределено) 
	
	Если СвойстваПодписи <> Неопределено Тогда
		ОписаниеОшибки = ОписаниеОшибки + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Порядковый номер подписи %1'"), СвойстваПодписи.ПорядковыйНомер);
		ПодписанныйОбъект = СвойстваПодписи.ПодписанныйОбъект;
		ПодписанныйОбъектМетаданные = ПодписанныйОбъект.Метаданные();
	Иначе
		ПодписанныйОбъект = Неопределено;
		ПодписанныйОбъектМетаданные = Неопределено;
	КонецЕсли;
	
	ИмяСобытия = НСтр("ru = 'Электронная подпись.Ошибка усовершенствования подписи'",
			ОбщегоНазначения.КодОсновногоЯзыка());
	ЗаписьЖурналаРегистрации(ИмяСобытия,
		УровеньЖурналаРегистрации.Информация,
		ПодписанныйОбъектМетаданные,
		ПодписанныйОбъект,
		ОписаниеОшибки);

КонецПроцедуры

// Только для внутреннего использования.
Функция ОбновитьУсовершенствованнуюПодпись(СвойстваПодписи) Экспорт
	
	ПредставлениеОшибки = ""; 
	Попытка
		ЭлектроннаяПодпись.ОбновитьПодпись(СвойстваПодписи.ПодписанныйОбъект, СвойстваПодписи, Истина);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = НСтр("ru = 'Не удалось записать подписи по причине:'")
			+ Символы.ПС + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	КонецПопытки;

	Возврат ПредставлениеОшибки;
	
КонецФункции

// Только для внутреннего использования.
Функция УсовершенствоватьПодписьВСервисе(Подпись, ПараметрыВыполнения)
	
	Результат = Новый Структура("Успех, ТекстОшибки, СвойстваПодписи", 
		Ложь,, ЭлектроннаяПодписьКлиентСервер.НовыеСвойстваПодписи());
	
	Если ПараметрыВыполнения.ТипПодписи <> Перечисления.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST Тогда
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru='Невозможно усовершенствовать подпись в приложении в Интернете до типа: %1.'"), 
				ПараметрыВыполнения.ТипПодписи);
		Возврат Результат;
	КонецЕсли;
		
	Попытка
		МодульСервисКриптографииDSSASNКлиентСервер = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSSASNКлиентСервер");
		СвойстваПодписи = МодульСервисКриптографииDSSASNКлиентСервер.ПолучитьСвойстваПодписи(
			Подпись, Новый Структура("ДанныеСертификата", Истина));
		Сертификат = СвойстваПодписи[0].Сертификат;
		СертификатКриптографии = Новый СертификатКриптографии(Сертификат);
		ТипПодписи = ТипПодписиСервиса(СвойстваПодписи[0].ТипПодписи);
	Исключение
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru='Не удалось усовершенствовать подпись в приложении в Интернете по причине:
			|%1'"), ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат Результат;
	КонецПопытки;
	
	Результат.СвойстваПодписи.ТипПодписи = ТипПодписи;
	
	СвойстваСертификата = ЭлектроннаяПодпись.СвойстваСертификата(СертификатКриптографии);
	
	Если ТипПодписи <> Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES Тогда
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru='Нельзя усовершенствовать подпись с типом %1 в приложении в Интернете'"), ТипПодписи);
			
		Если ТипПодписи = Перечисления.ТипыПодписиКриптографии.ОбычнаяCMS Тогда
			Результат.СвойстваПодписи.СрокДействияПоследнейМеткиВремени = СвойстваСертификата.ДействителенДо;
		КонецЕсли;
		Возврат Результат;
	КонецЕсли;
	
	Если Не ПараметрыВыполнения.ИгнорироватьСрокДействияСертификата 
		И СвойстваСертификата.ДействителенДо < ТекущаяДатаСеанса() Тогда 
		СведенияОСертификате =
			ЭлектроннаяПодписьСлужебныйКлиентСервер.СведенияОСертификатеСтрокой(СвойстваСертификата);
	
		Результат.СвойстваПодписи.СрокДействияПоследнейМеткиВремени = СвойстваСертификата.ДействителенДо;
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru='Срок действия сертификата подписи истек:
			|%1'"), СведенияОСертификате);
			
		Возврат Результат;
		
	КонецЕсли;
	
	МодульСервисКриптографииDSS = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSS");
	РезультатПроверкиСертификата = МодульСервисКриптографииDSS.ПроверитьСертификат(
		ПараметрыВыполнения.СлужебнаяУчетнаяЗаписьDSS, Сертификат);
			
	Если РезультатПроверкиСертификата.Выполнено = Ложь Или РезультатПроверкиСертификата.Результат <> Истина Тогда
		СведенияОСертификате =
			ЭлектроннаяПодписьСлужебныйКлиентСервер.СведенияОСертификатеСтрокой(СвойстваСертификата);
		Результат.СвойстваПодписи.СрокДействияПоследнейМеткиВремени = СвойстваСертификата.ДатаОкончания;
		Результат.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru='Не удалось проверить сертификат в приложении в Интернете, подробности см. в журнале регистрации:
				|%1'"), СведенияОСертификате);
	
		Возврат Результат;
	КонецЕсли;
	
	ПараметрыПодписи = ПараметрыВыполнения.ПараметрыПодписиCAdEST;
	РезультатЗапроса = МодульСервисКриптографииDSS.УсовершенствоватьПодпись(
		ПараметрыВыполнения.СлужебнаяУчетнаяЗаписьDSS, Подпись, ПараметрыПодписи);
	Если РезультатЗапроса.Выполнено Тогда
		АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(
			РезультатЗапроса.Результат, Ложь, Истина);
		Если Не ЗначениеЗаполнено(АлгоритмПодписи) Тогда
			Результат.ТекстОшибки = НСтр("ru='При усовершенствовании подписи в приложении в Интернете получен некорректный ответ:'") 
				+ Символы.ПС + РезультатЗапроса.Результат;
		Иначе
			Результат.Успех = Истина;
			Результат.СвойстваПодписи.ТипПодписи = ПараметрыВыполнения.ТипПодписи;
			Результат.СвойстваПодписи.Подпись = РезультатЗапроса.Результат;
		КонецЕсли;
	Иначе
		Результат.ТекстОшибки = 
			НСтр("ru='Не удалось усовершенствовать подпись в приложении в Интернете. Описание ошибки см. в журнале регистрации.'");
	КонецЕсли;
	
	Если РезультатЗапроса.МаркерОбновлен Тогда
		ПараметрыВыполнения.СлужебнаяУчетнаяЗаписьDSS = РезультатЗапроса.НастройкиПользователя;
	КонецЕсли;
		
	Возврат Результат;
	
КонецФункции 

// Только для внутреннего использования.
Функция ТипПодписиСервиса(ТипПодписи)
	
	Если ТипПодписи = "CAdES-BES" Тогда
		Возврат Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES;
	ИначеЕсли ТипПодписи = "CadES-T" Тогда
		Возврат Перечисления.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST;
	ИначеЕсли ТипПодписи = "CMS" Тогда
		Возврат Перечисления.ТипыПодписиКриптографии.ОбычнаяCMS;
	ИначеЕсли ТипПодписи = "CAdES-Av3" Тогда
		Возврат Перечисления.ТипыПодписиКриптографии.АрхивнаяCAdESAv3;
	ИначеЕсли ТипПодписи = "CadES-X Long Type 2" Тогда
		Возврат Перечисления.ТипыПодписиКриптографии.РасширеннаяДолгосрочнаяCAdESXLongType2;
	ИначеЕсли ТипПодписи = "CadES-С" Тогда
		Возврат Перечисления.ТипыПодписиКриптографии.СПолнымНаборомПроверочныхДанныхCAdESC;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Только для внутреннего использования.
Функция НастройкиСлужебнойУчетнойЗаписиДляУсовершенствованияПодписей(ИдентификаторФормы = Неопределено) Экспорт
	
	НастройкиСлужебнойУчетнойЗаписи = Новый Структура("СлужебнаяУчетнаяЗаписьDSS, Ошибка, ПараметрыПодписиCAdEST");
	
	МодульСервисКриптографииDSS = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSS");
	НастройкиПодключения = МодульСервисКриптографииDSS.НастройкиПодключенияСлужебнойУчетнойЗаписи();
	
	Если НастройкиПодключения.Свойство("Ошибка") 
		И ЗначениеЗаполнено(НастройкиПодключения.Ошибка) Тогда
		НастройкиСлужебнойУчетнойЗаписи.Ошибка = НастройкиПодключения.Ошибка;
		Возврат НастройкиСлужебнойУчетнойЗаписи;
	КонецЕсли;
	
	МодульСервисКриптографииDSSКлиентСервер = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSSКлиентСервер");
	Результат = МодульСервисКриптографииDSS.АутентификацияПоЛогину(НастройкиПодключения.Результат);

	Если Результат.Выполнено Тогда
		АдресаСерверовМетокВремени = МодульСервисКриптографииDSSКлиентСервер.ПолучитьСервераШтамповВремени(
			Результат.НастройкиПользователя);
			
		Если АдресаСерверовМетокВремени.Количество() = 0 Тогда
			НастройкиСлужебнойУчетнойЗаписи.Ошибка =
				НСтр("ru = 'В служебной учетной записи нет доступных адресов серверов меток времени'");
			Возврат НастройкиСлужебнойУчетнойЗаписи;
		КонецЕсли;
		
		Если ИдентификаторФормы = Неопределено Тогда
			НастройкиСлужебнойУчетнойЗаписи.СлужебнаяУчетнаяЗаписьDSS = Результат.НастройкиПользователя;
		Иначе
			НастройкиСлужебнойУчетнойЗаписи.СлужебнаяУчетнаяЗаписьDSS = 
				ПоместитьВоВременноеХранилище(Результат.НастройкиПользователя, ИдентификаторФормы);
		КонецЕсли;
		
	Иначе
		НастройкиСлужебнойУчетнойЗаписи.Ошибка = Результат.Ошибка;
		Возврат НастройкиСлужебнойУчетнойЗаписи;
	КонецЕсли;
		
	НастройкиСлужебнойУчетнойЗаписи.ПараметрыПодписиCAdEST = 
		МодульСервисКриптографииDSSКлиентСервер.ПолучитьСвойствоПодписиCAdES(
			"T", Истина, Ложь, "Подпись", АдресаСерверовМетокВремени[0].Адрес);

	Возврат НастройкиСлужебнойУчетнойЗаписи;
	
КонецФункции

// Только для внутреннего использования.
Функция УсовершенствоватьНаСторонеСервера(Параметры) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Успех", Ложь);
	Результат.Вставить("ТекстОшибки", "");
	Результат.Вставить("СвойстваПодписи", ЭлектроннаяПодписьКлиентСервер.НовыеСвойстваПодписи());
	Результат.Вставить("АлгоритмПодписи");
	Результат.Вставить("ОшибкаПриСозданииМенеджераКриптографии", Ложь);
	Результат.Вставить("ОперацияНачалась", Параметры.ОперацияНачалась);
	
	Подпись = Параметры.ЭлементДанныхДляСервера.Подпись;
	Если ТипЗнч(Подпись) = Тип("Строка") Тогда
		Попытка
			Подпись = ПолучитьИзВременногоХранилища(Подпись);
		Исключение
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			Результат.ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаголовокОшибкиПолученияДанных("ПродлениеСрокаДействияПодписи")
			 + Символы.ПС + ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
			Возврат Результат;
		КонецПопытки;
	КонецЕсли;
	
	АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(Подпись);
	Результат.АлгоритмПодписи = АлгоритмПодписи;
	
	Если Параметры.ЭтоМодельСервисаСДоступнымУсовершенствованием Тогда
	
		ПараметрыВыполнения = Новый Структура;
		ПараметрыВыполнения.Вставить("ТипПодписи", Параметры.ТипПодписи);
		ПараметрыВыполнения.Вставить("ПараметрыПодписиCAdEST", Параметры.ПараметрыПодписиCAdEST);
		ПараметрыВыполнения.Вставить("СлужебнаяУчетнаяЗаписьDSS", Параметры.СлужебнаяУчетнаяЗаписьDSS);
		ПараметрыВыполнения.Вставить("ИгнорироватьСрокДействияСертификата", Параметры.ИгнорироватьСрокДействияСертификата);
		
		РезультатЗапроса = УсовершенствоватьПодписьВСервисе(Подпись, ПараметрыВыполнения);
		ЗаполнитьЗначенияСвойств(Результат, РезультатЗапроса);

		Если Результат.Успех Тогда
			Если Параметры.ЭлементДанныхДляСервера.Свойство("ПодписанныйОбъект") Тогда
				
				Результат.СвойстваПодписи.ПодписанныйОбъект = Параметры.ЭлементДанныхДляСервера.ПодписанныйОбъект;
				Результат.СвойстваПодписи.ПорядковыйНомер = Параметры.ЭлементДанныхДляСервера.ПорядковыйНомер;
				ПредставлениеОшибки = ОбновитьУсовершенствованнуюПодпись(Результат.СвойстваПодписи);
				
				Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
					Результат.Успех = Ложь;
					Результат.ТекстОшибки = ПредставлениеОшибки;
					Возврат Результат;
				КонецЕсли;
				
				Если ЗначениеЗаполнено(Результат.СвойстваПодписи.Подпись) Тогда
					ЗарегистрироватьУсовершенствованиеПодписиВЖурнале(Результат.СвойстваПодписи);
				КонецЕсли;
				
			КонецЕсли; 
		Иначе
			Возврат Результат;
		КонецЕсли;
		
		ПоместитьВоВременноеХранилище(ПараметрыВыполнения.СлужебнаяУчетнаяЗаписьDSS, Параметры.СлужебнаяУчетнаяЗаписьDSSАдрес);
		
	Иначе
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.ОписаниеОшибки = Новый Структура;
		ПараметрыСоздания.АлгоритмПодписи = АлгоритмПодписи;
		
		МенеджерКриптографии = МенеджерКриптографии("ПродлениеСрокаДействияПодписи", ПараметрыСоздания);
		
		Если МенеджерКриптографии = Неопределено Тогда
			Результат.ТекстОшибки = ПараметрыСоздания.ОписаниеОшибки;
			Результат.ОшибкаПриСозданииМенеджераКриптографии = Истина;
			Возврат Результат;
		КонецЕсли;
		
		МенеджерКриптографии.АдресаСерверовМетокВремени = ЭлектроннаяПодпись.ОбщиеНастройки().АдресаСерверовМетокВремени;
		
		ДополнительныеПараметры = Новый Структура;
		ДополнительныеПараметры.Вставить("МенеджерКриптографии", МенеджерКриптографии);
		ДополнительныеПараметры.Вставить("ИгнорироватьСрокДействияСертификата", Параметры.ИгнорироватьСрокДействияСертификата);
		
		Если Параметры.ЭлементДанныхДляСервера.Свойство("ПодписанныйОбъект") Тогда
			РезультатЗапроса = ЭлектроннаяПодпись.УсовершенствоватьПодписьОбъекта(Параметры.ЭлементДанныхДляСервера.ПодписанныйОбъект,
				Параметры.ЭлементДанныхДляСервера.ПорядковыйНомер, Параметры.ТипПодписи,
				Параметры.ДобавитьАрхивнуюМеткуВремени, Параметры.ИдентификаторФормы, ДополнительныеПараметры);
		Иначе
			РезультатЗапроса = ЭлектроннаяПодпись.УсовершенствоватьПодпись(Подпись, Параметры.ТипПодписи,
				Параметры.ДобавитьАрхивнуюМеткуВремени, ДополнительныеПараметры);
		КонецЕсли;
		
		ЗаполнитьЗначенияСвойств(Результат, РезультатЗапроса);
		
	КонецЕсли;
	
	Если Не Результат.Успех Тогда
		Возврат Результат;
	КонецЕсли;
	
	Результат.ОперацияНачалась = Истина;
	
	Возврат Результат;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обновление информационной базы.

////////////////////////////////////////////////////////////////////////////////
// Работа с XMLDSig

// Подписывает сообщение, подставляя в КонвертXML данные подписи.
//
// Параметры:
//  КонвертXML             - см. ЭлектроннаяПодписьКлиент.КонвертXML
//  ПараметрыXMLDSig       - см. ЭлектроннаяПодписьКлиент.ПараметрыXMLDSig
//  СертификатКриптографии - СертификатКриптографии - используемый сертификат криптографии.
//  МенеджерКриптографии   - МенеджерКриптографии   - менеджер криптографии,
//                           который соответствует закрытому ключу сертификата с установленным паролем.
//
// Возвращаемое значение:
//  Строка - подписанный КонвертXML.
//
Функция Подписать(Знач КонвертXML, ПараметрыXMLDSig, СертификатКриптографии, МенеджерКриптографии) Экспорт
	
	Пароль = МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу;
	
	ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
	
	СвойстваКриптопровайдера = СвойстваКриптопровайдера(МенеджерКриптографии);
	ОбъектКомпоненты.ПутьККриптопровайдеру = СвойстваКриптопровайдера.Путь;
	
	СвойстваКонвертаXML = СвойстваКонвертаXML(КонвертXML, ПараметрыXMLDSig, Ложь);
	Если СвойстваКонвертаXML <> Неопределено
	   И ЗначениеЗаполнено(СвойстваКонвертаXML.ТекстОшибки) Тогда
		ВызватьИсключение СвойстваКонвертаXML.ТекстОшибки;
	КонецЕсли;
	
	СертификатКриптографииBase64 = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатКриптографииBase64(
		СертификатКриптографии.Выгрузить());
	
	ДанныеАлгоритмаПодписания = Новый Структура(Новый ФиксированнаяСтруктура(ПараметрыXMLDSig));
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ПроверитьВыбратьАлгоритмПодписи(
		СертификатКриптографииBase64, ДанныеАлгоритмаПодписания, Истина, СвойстваКонвертаXML);
	
	КонвертXML = СтрЗаменить(КонвертXML, "%BinarySecurityToken%", СертификатКриптографииBase64);
	КонвертXML = СтрЗаменить(КонвертXML, "%SignatureMethod%", ДанныеАлгоритмаПодписания.ВыбранныйАлгоритмПодписи);
	КонвертXML = СтрЗаменить(КонвертXML, "%DigestMethod%",    ДанныеАлгоритмаПодписания.ВыбранныйАлгоритмХеширования);
	
	Если СвойстваКонвертаXML <> Неопределено Тогда
		Для Индекс = 0 По СвойстваКонвертаXML.ХешируемыеОбласти.ВГраница() Цикл
			ХешируемаяОбласть = СвойстваКонвертаXML.ХешируемыеОбласти[Индекс];
			КанонизированныйТекстXMLBody = КанонизированныйТекстXML(ОбъектКомпоненты,
				СвойстваКонвертаXML.ОбластиBody[Индекс], ХешируемаяОбласть.АлгоритмыТрансформации);
			АтрибутDigestValue = РезультатHash(ОбъектКомпоненты, КанонизированныйТекстXMLBody,
				ДанныеАлгоритмаПодписания.OIDВыбранногоАлгоритмаХеширования, СвойстваКриптопровайдера.Тип);

			КонвертXML = СтрЗаменить(КонвертXML, ХешируемаяОбласть.ЗначениеХеша, АтрибутDigestValue);
		КонецЦикла;
	Иначе
		КанонизированныйТекстXMLBody = C14N(ОбъектКомпоненты, КонвертXML,
			ДанныеАлгоритмаПодписания.XPathПодписываемыйТег);
		
		АтрибутDigestValue = РезультатHash(ОбъектКомпоненты, КанонизированныйТекстXMLBody,
			ДанныеАлгоритмаПодписания.OIDВыбранногоАлгоритмаХеширования, СвойстваКриптопровайдера.Тип);

		КонвертXML = СтрЗаменить(КонвертXML, "%DigestValue%", АтрибутDigestValue);
	КонецЕсли;
	
	Если СвойстваКонвертаXML = Неопределено Тогда
		КанонизированныйТекстXMLSignedInfo = C14N(ОбъектКомпоненты,
			КонвертXML, ДанныеАлгоритмаПодписания.XPathSignedInfo);
	Иначе
		ОбластьSignedInfo = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбластьXML(КонвертXML,
			СвойстваКонвертаXML.ОбластьSignedInfo.ИмяЭлемента);
		ОбластьSignedInfo.ПространстваИменДоУзла =
			СвойстваКонвертаXML.ОбластьSignedInfo.ПространстваИменДоУзла;
		
		Если ЗначениеЗаполнено(ОбластьSignedInfo.ТекстОшибки) Тогда
			ВызватьИсключение ОбластьSignedInfo.ТекстОшибки;
		КонецЕсли;
		
		КанонизированныйТекстXMLSignedInfo = КанонизированныйТекстXML(ОбъектКомпоненты,
			ОбластьSignedInfo,
			ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СвойстваКонвертаXML.АлгоритмКанонизации));
	КонецЕсли;
	
	АтрибутSignatureValue = РезультатSign(ОбъектКомпоненты,
		КанонизированныйТекстXMLSignedInfo,
		СертификатКриптографии,
		Пароль);
	
	КонвертXML = СтрЗаменить(КонвертXML, "%SignatureValue%", АтрибутSignatureValue);
	
	Возврат КонвертXML;
	
КонецФункции

// Возвращается сертификат, с помощью которого была произведена подпись.
// Если проверка подписи завершилась неудачно, генерируется исключительная ситуация.
//
// Параметры:
//  КонвертXML           - см. ЭлектроннаяПодписьКлиент.КонвертXML
//  ПараметрыXMLDSig     - см. ЭлектроннаяПодписьКлиент.ПараметрыXMLDSig
//  МенеджерКриптографии - МенеджерКриптографии - менеджер криптографии,
//                         который поддерживает алгоритмы проверяемой подписи.
//  СвойстваКонвертаXML  - см. СвойстваКонвертаXML
//
// Возвращаемое значение:
//  Структура:
//   * Сертификат     - СертификатКриптографии
//   * ДатаПодписания - Дата
//
Функция ПроверитьПодпись(Знач КонвертXML, ПараметрыXMLDSig, МенеджерКриптографии, СвойстваКонвертаXML = Неопределено) Экспорт
	
	ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
	
	СвойстваКриптопровайдера = СвойстваКриптопровайдера(МенеджерКриптографии);
	ОбъектКомпоненты.ПутьККриптопровайдеру = СвойстваКриптопровайдера.Путь;
	ДанныеАлгоритмаПодписания = Новый Структура(Новый ФиксированнаяСтруктура(ПараметрыXMLDSig));
	
	Если СвойстваКонвертаXML = Неопределено Тогда
		КанонизированныйТекстXMLSignedInfo = C14N(ОбъектКомпоненты,
			КонвертXML, ДанныеАлгоритмаПодписания.XPathSignedInfo);
		КанонизированныйТекстXMLBody = C14N(ОбъектКомпоненты,
			КонвертXML, ДанныеАлгоритмаПодписания.XPathПодписываемыйТег);
		СертификатКриптографииBase64 = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатИзКонвертаSOAP(КонвертXML);
		ЗначениеПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.НайтиВXML(КонвертXML, "SignatureValue");
		ЗначениеХеша    = ЭлектроннаяПодписьСлужебныйКлиентСервер.НайтиВXML(КонвертXML, "DigestValue");
	Иначе
		КанонизированныйТекстXMLSignedInfo = КанонизированныйТекстXML(ОбъектКомпоненты,
			СвойстваКонвертаXML.ОбластьSignedInfo,
			ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СвойстваКонвертаXML.АлгоритмКанонизации));
		
		ЗначениеПодписи = СвойстваКонвертаXML.ЗначениеПодписи;
		СертификатКриптографииBase64 = СвойстваКонвертаXML.Сертификат.ЗначениеСертификата;
		
	КонецЕсли;
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ПроверитьВыбратьАлгоритмПодписи(
		СертификатКриптографииBase64, ДанныеАлгоритмаПодписания, Истина, СвойстваКонвертаXML);
		
	ПодписьВерна = РезультатVerifySign(ОбъектКомпоненты,
		КанонизированныйТекстXMLSignedInfo,
		ЗначениеПодписи,
		СертификатКриптографииBase64,
		СвойстваКриптопровайдера.Тип);

	Если СвойстваКонвертаXML <> Неопределено Тогда
		
		Счетчик = 1;
		Для Каждого ХешируемаяОбласть Из СвойстваКонвертаXML.ХешируемыеОбласти Цикл
			КанонизированныйТекстXMLBody = КанонизированныйТекстXML(ОбъектКомпоненты,
				СвойстваКонвертаXML.ОбластиBody[Счетчик-1], ХешируемаяОбласть.АлгоритмыТрансформации);
			ЗначениеХеша = ХешируемаяОбласть.ЗначениеХеша; 
			
			АтрибутDigestValue = РезультатHash(ОбъектКомпоненты,
				КанонизированныйТекстXMLBody,
				ДанныеАлгоритмаПодписания.OIDВыбранногоАлгоритмаХеширования,
				СвойстваКриптопровайдера.Тип);
				
			ХешСовпадает = (АтрибутDigestValue = ЗначениеХеша);
			
			Если Не ХешСовпадает Или Не ПодписьВерна Тогда
				ВызватьИсключение ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиПроверкиПодписиXML(ПодписьВерна, ХешСовпадает);
			КонецЕсли;
			Счетчик = Счетчик + 1;
		КонецЦикла;
		
		Возврат РезультатПроверкиПодписиXML(СертификатКриптографииBase64);
		
	КонецЕсли;
	
	АтрибутDigestValue = РезультатHash(ОбъектКомпоненты,
		КанонизированныйТекстXMLBody,
		ДанныеАлгоритмаПодписания.OIDВыбранногоАлгоритмаХеширования,
		СвойстваКриптопровайдера.Тип);
	
	ХешСовпадает = (АтрибутDigestValue = ЗначениеХеша);
	
	Если ХешСовпадает И ПодписьВерна Тогда
		Возврат РезультатПроверкиПодписиXML(СертификатКриптографииBase64);
	Иначе
		ВызватьИсключение ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиПроверкиПодписиXML(ПодписьВерна, ХешСовпадает);
	КонецЕсли;
	
КонецФункции

Функция РезультатПроверкиПодписиXML(СертификатКриптографииBase64)
	
	ДвоичныеДанные = Base64Значение(СертификатКриптографииBase64);

	Результат = Новый Структура;
	Результат.Вставить("Сертификат", Новый СертификатКриптографии(ДвоичныеДанные));
	Результат.Вставить("ДатаПодписания", Неопределено);

	Возврат Результат;
		
КонецФункции

// Вычисляет и проверят свойства конверта XML для подписания и проверки подписи.
//
// Параметры:
//  КонвертXML             - см. ЭлектроннаяПодписьКлиент.КонвертXML
//  ПараметрыXMLDSig       - см. ЭлектроннаяПодписьКлиент.ПараметрыXMLDSig
//  ПроверкаПодписи  - Булево - когда Ложь, тогда в конверте проверяется наличие
//                                параметров для подстановки и алгоритмов канонизации.
//                              Когда Истина, тогда - в конверте корректность алгоритмов
//                                канонизации, подписания и хеширования, а также заполненность
//                                значений подписи, хеша и сертификата.
//
// Возвращаемое значение:
//   см. ВозвращаемыеСвойстваКонвертаXML
//
Функция СвойстваКонвертаXML(КонвертXML, ПараметрыXMLDSig, ПроверкаПодписи) Экспорт
	
	Если ЗначениеЗаполнено(ПараметрыXMLDSig.XPathSignedInfo)
	 Или ЗначениеЗаполнено(ПараметрыXMLDSig.XPathПодписываемыйТег) Тогда
		Возврат Неопределено; // Обратная совместимость.
	КонецЕсли;
	
	ЧтениеXML = Новый ЧтениеXML;
	ЧтениеXML.УстановитьСтроку(КонвертXML);
	
	ПостроительDOM = Новый ПостроительDOM;
	ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML);
	
	ЧтениеXML.Закрыть();
	
	СвойстваКонвертаXML = СлужебныеСвойстваКонвертаXML(ПроверкаПодписи);
	
	ИмяУзлаПодписи = "Signature";
	ИмяПространстваИменУзлаПодписи = "http://www.w3.org/2000/09/xmldsig#";
	ПространстваИменДоУзлаSignatureВключительно = Новый Массив;
	
	ИсключаемыеУзлы = Новый Массив;
	НомерSignature = 0;
	Пока Истина Цикл
		НомерSignature = НомерSignature + 1;
		УзелSignature = НайтиУзелПоИмени(ДокументDOM,
			ИмяУзлаПодписи, ИмяПространстваИменУзлаПодписи,
			СвойстваКонвертаXML.ТекстОшибки, ИсключаемыеУзлы, ПространстваИменДоУзлаSignatureВключительно);
		Если УзелSignature = Неопределено Тогда
			Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
		КонецЕсли;
		
		// Если текстовое содержимое узла уже содержит значение подписи, значит используется наложение нескольких подписей и
		// нужно найти другой узел
		Если СтрНайти(УзелSignature.ТекстовоеСодержимое, "%SignatureValue%") = 0 И Не ПроверкаПодписи Тогда
			ИсключаемыеУзлы.Добавить(УзелSignature);
			Продолжить;
		Иначе
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого ДочернийУзел Из УзелSignature.ДочерниеУзлы Цикл
		Если ДочернийУзел.ЛокальноеИмя = "SignedInfo" Тогда
			Если Не ОбработатьУзелSignedInfo(ДочернийУзел, СвойстваКонвертаXML) Тогда
				Прервать;
			КонецЕсли;
		ИначеЕсли ДочернийУзел.ЛокальноеИмя = "SignatureValue" Тогда
			Если Не ПолучитьЗначение(ДочернийУзел, СвойстваКонвертаXML, "ЗначениеПодписи") Тогда
				Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
			КонецЕсли;
		ИначеЕсли ДочернийУзел.ЛокальноеИмя = "KeyInfo" Тогда
			Если Не ОбработатьУзелKeyInfo(ДочернийУзел, СвойстваКонвертаXML) Тогда
				Прервать;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если ЗначениеЗаполнено(СвойстваКонвертаXML.ТекстОшибки) Тогда
		Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
	КонецЕсли;
	
	Для Каждого КлючИЗначение Из СвойстваКонвертаXML.ОбязательныеУзлы Цикл
		Если КлючИЗначение.Значение <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ЧастиИмени = СтрРазделить(КлючИЗначение.Ключ, "_");
		Если ЧастиИмени.Количество() > 1 Тогда
			СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'В документе XML не найден узел ""%1"" в узле ""%2"".'"), КлючИЗначение.Ключ);
		Иначе
			СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'В документе XML не найден узел ""%1"".'"), ЧастиИмени[0]);
		КонецЕсли;
		Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
	КонецЦикла;
	
	Если ЗначениеЗаполнено(СвойстваКонвертаXML.Сертификат.ИдентификаторУзла)
	   И ЗначениеЗаполнено(СвойстваКонвертаXML.Сертификат.ЗначениеСертификата) Тогда
		
		СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В документе XML сертификат объявлен дважды:
			           |- в виде URI ссылки на элемент ""%1"";
			           |- в виде данных ""%2"".'"),
			СвойстваКонвертаXML.Сертификат.ИдентификаторУзла,
			СвойстваКонвертаXML.Сертификат.ЗначениеСертификата);
		
		Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
		
	ИначеЕсли Не ЗначениеЗаполнено(СвойстваКонвертаXML.Сертификат.ИдентификаторУзла)
	        И Не ЗначениеЗаполнено(СвойстваКонвертаXML.Сертификат.ЗначениеСертификата) Тогда
		
		СвойстваКонвертаXML.ТекстОшибки =
			НСтр("ru = 'В документе XML не найден сертификат.'");
		
		Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
	КонецЕсли;

	ИсключаемыеУзлы.Добавить(УзелSignature);
	
	Если ЗначениеЗаполнено(СвойстваКонвертаXML.Сертификат.ИдентификаторУзла) Тогда
		УзелСертификат = НайтиУзелПоИдентификатору(ДокументDOM,
			СвойстваКонвертаXML.Сертификат.ИдентификаторУзла,
			СвойстваКонвертаXML.ТекстОшибки,
			ИсключаемыеУзлы);
		Если ЗначениеЗаполнено(СвойстваКонвертаXML.ТекстОшибки) Тогда
			Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
		КонецЕсли;
		Если Не ПолучитьЗначение(УзелСертификат, СвойстваКонвертаXML,
					"ЗначениеСертификата", СвойстваКонвертаXML.Сертификат) Тогда
			Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
		КонецЕсли;
		ИсключаемыеУзлы.Добавить(УзелСертификат);
	КонецЕсли;
	
	УзлыBody = Новый Массив;
	
	Для Каждого ХешируемаяОбласть Из СвойстваКонвертаXML.ХешируемыеОбласти Цикл
		ПространстваИменДоУзлаBody = Новый Массив;
		УзелBody = НайтиУзелПоИдентификатору(ДокументDOM,
			ХешируемаяОбласть.ИдентификаторУзла,
			СвойстваКонвертаXML.ТекстОшибки,
			ИсключаемыеУзлы,
			ПространстваИменДоУзлаBody);
		Если ЗначениеЗаполнено(СвойстваКонвертаXML.ТекстОшибки) Тогда
			Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
		КонецЕсли;
		ИсключаемыеУзлы.Добавить(УзелBody);
		УзлыBody.Добавить(УзелBody);
	КонецЦикла;
	
	Для Каждого ХешируемаяОбласть Из СвойстваКонвертаXML.ХешируемыеОбласти Цикл
		УзелBody2 = НайтиУзелПоИдентификатору(ДокументDOM,
			ХешируемаяОбласть.ИдентификаторУзла,
			СвойстваКонвертаXML.ТекстОшибки, ИсключаемыеУзлы, , Истина);
		Если УзелBody2 <> Неопределено Тогда
			Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
		КонецЕсли;
	КонецЦикла;
	
	УзелSignedInfo = СвойстваКонвертаXML.УникальныеУзлы.SignedInfo; // ЭлементDOM
	ОбластьSignedInfo = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбластьXML(КонвертXML,
		УзелSignedInfo.ИмяЭлемента, НомерSignature);
	Если ЗначениеЗаполнено(ОбластьSignedInfo.ТекстОшибки) Тогда
		СвойстваКонвертаXML.ТекстОшибки = ОбластьSignedInfo.ТекстОшибки;
		Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
	КонецЕсли;
	ОбластьSignedInfo.ПространстваИменДоУзла = ПространстваИменДоУзлаSignatureВключительно;
	СвойстваКонвертаXML.ОбластьSignedInfo = ОбластьSignedInfo;
	
	Для Каждого ЭлементОбластьBody Из УзлыBody Цикл
		ОбластьBody = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбластьXML(КонвертXML,
			ЭлементОбластьBody.ИмяЭлемента);
		Если ЗначениеЗаполнено(ОбластьBody.ТекстОшибки) Тогда
			СвойстваКонвертаXML.ТекстОшибки = ОбластьBody.ТекстОшибки;
			Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
		КонецЕсли;
		ОбластьBody.ПространстваИменДоУзла = ПространстваИменДоУзлаBody;
		СвойстваКонвертаXML.ОбластиBody.Добавить(ОбластьBody);
	КонецЦикла;
	
	Возврат ВозвращаемыеСвойстваКонвертаXML(СвойстваКонвертаXML);
	
КонецФункции

Функция ОбъектВнешнейКомпонентыExtraCryptoAPI()
	
	ОписаниеКомпоненты = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты();
	ОбъектКомпоненты = ОбщегоНазначения.ПодключитьКомпонентуИзМакета(ОписаниеКомпоненты.ИмяОбъекта,
		ОписаниеКомпоненты.ПолноеИмяМакета);
	
	Если ОбъектКомпоненты = Неопределено Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось подключить внешнюю компоненту %1.'"), ОписаниеКомпоненты.ИмяОбъекта);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	НастроитьКомпоненту(ОбъектКомпоненты);
	
	Возврат ОбъектКомпоненты;
	
КонецФункции

Процедура НастроитьКомпоненту(ОбъектКомпоненты)
	
	Попытка
		ОбъектКомпоненты.СоответствиеOID =
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ИдентификаторыАлгоритмовХешированияИОткрытогоКлюча();
	Исключение
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось установить свойство %1 компоненты %2 по причине:
				|%3'"), "СоответствиеOID", "ExtraCryptoAPI", ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
КонецПроцедуры

// Подписывает данные и возвращает подпись с данными или без них.
//
// Параметры:
//  Данные - Строка - произвольная строка для подписания,
//         - ДвоичныеДанные - двоичные данные для подписания.
//
//  ПараметрыCMS            - Структура - возвращается функцией ЭлектроннаяПодпись.ПараметрыCMS.
//  СертификатКриптографии  - СертификатКриптографии - используемый сертификат криптографии.
//  МенеджерКриптографии    - МенеджерКриптографии   - используемый менеджер криптографии.
// 
// Возвращаемое значение:
//  Строка - строка в формате Base64.
//
Функция ПодписатьCMS(Знач Данные, ПараметрыCMS, СертификатКриптографии, МенеджерКриптографии) Экспорт
	
	Пароль = МенеджерКриптографии.ПарольДоступаКЗакрытомуКлючу;
	
	ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
	
	СвойстваКриптопровайдера = СвойстваКриптопровайдера(МенеджерКриптографии);
	ОбъектКомпоненты.ПутьККриптопровайдеру = СвойстваКриптопровайдера.Путь;
	
	АтрибутSignatureValue = РезультатCMSSign(ОбъектКомпоненты,
		Данные,
		ПараметрыCMS,
		СертификатКриптографии,
		Пароль);
	
	Возврат АтрибутSignatureValue;
	
КонецФункции

Функция ПроверитьПодписьCMS(Подпись, Данные, ПараметрыCMS, МенеджерКриптографии) Экспорт
	
	ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
	
	СвойстваКриптопровайдера = СвойстваКриптопровайдера(МенеджерКриптографии);
	ОбъектКомпоненты.ПутьККриптопровайдеру = СвойстваКриптопровайдера.Путь;
	
	Результат = РезультатCMSVerifySign(ОбъектКомпоненты,
		Подпись,
		Данные,
		ПараметрыCMS,
		СвойстваКриптопровайдера.Тип);
	
	Возврат Результат;
	
КонецФункции

// Установленные криптопровайдеры.
// 
// Возвращаемое значение:
//  Структура:
//   * ПроверкаВыполнена - Булево
//   * Ошибка - Строка - если ПроверкаВыполнена = Ложь
//   * Криптопровайдеры - Массив из Структура:
//      ** Ссылка - Неопределено, СправочникСсылка.СертификатыКлючейЭлектроннойПодписиИШифрования
//      ** Представление - Строка
//      ** ИмяПрограммы - Строка
//      ** ТипПрограммы - Число
//      ** АлгоритмПодписи - Строка
//      ** АлгоритмХеширования - Строка
//      ** АлгоритмШифрования - Строка
//      ** Идентификатор - Строка
//      ** ПутьКПрограмме - Строка
//      ** Версия - Строка - версия библиотеки
//      ** Лицензия - Булево - есть ли лицензия к программе
//      ** Автоопределение - Булево
//
Функция УстановленныеКриптопровайдеры(ОбъектКомпоненты = Неопределено) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("ПроверкаВыполнена", Ложь);
	Результат.Вставить("Криптопровайдеры", Новый Массив);
	Результат.Вставить("Ошибка", "");
	
	Настройки = ЭлектроннаяПодпись.ОбщиеНастройки();
	
	Если (Не ОбщегоНазначения.ИнформационнаяБазаФайловая() Или ОбщегоНазначения.КлиентПодключенЧерезВебСервер())
		И Не ЭлектроннаяПодпись.ПроверятьЭлектронныеПодписиНаСервере()
		И Не ЭлектроннаяПодпись.СоздаватьЭлектронныеПодписиНаСервере() Тогда
			Результат.Ошибка = НСтр("ru = 'Не настроена криптография на сервере.'");
			Возврат Результат;
	КонецЕсли;
	
	Попытка
		Если ОбъектКомпоненты = Неопределено Тогда
			ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
		КонецЕсли; 
		РезультатСписок = ОбъектКомпоненты.ПолучитьСписокКриптопровайдеров();
		ПрограммыПоИменамСТипом = Настройки.ПрограммыПоИменамСТипом;
		УстановленныеКриптопровайдеры = ЭлектроннаяПодписьСлужебныйКлиентСервер.УстановленныеКриптопровайдерыИзОтветаКомпоненты(
			РезультатСписок, ПрограммыПоИменамСТипом, Ложь);
		Результат.ПроверкаВыполнена = Истина;
		Результат.Криптопровайдеры = УстановленныеКриптопровайдеры;
	Исключение
		Результат.ПроверкаВыполнена = Ложь;
		Результат.Ошибка = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;
	
	Возврат Результат;
		
КонецФункции

Функция СвойстваКриптопровайдера(МенеджерКриптографии)
	
	ИнформацияМодуляКриптографии = МенеджерКриптографии.ПолучитьИнформациюМодуляКриптографии();
	
	ИмяКриптопровайдера = ИнформацияМодуляКриптографии.Имя;
	
	ОписаниеОшибки = "";
	КриптопровайдерыРезультат = ЭлектроннаяПодписьСлужебныйПовтИсп.УстановленныеКриптопровайдеры();
	ПрограммыАвто = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатПоискаКриптопровайдеров(КриптопровайдерыРезультат, ИмяКомпьютера());
		
	Если ТипЗнч(ПрограммыАвто) = Тип("Строка") Тогда
		ОписаниеОшибки = ПрограммыАвто;
		ПрограммыАвто = Неопределено;
	КонецЕсли;
	
	ОписаниеПрограммы = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеПрограммыПоИмениКриптопровайдера(ИмяКриптопровайдера,
		ЭлектроннаяПодпись.ОбщиеНастройки().ОписанияПрограмм, ПрограммыАвто); // см. ЭлектроннаяПодписьСлужебныйПовтИсп.ОписаниеПрограммы
	
	Если ОписаниеПрограммы = Неопределено Тогда
		Если Не ПустаяСтрока(ОписаниеОшибки) Тогда
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось определить тип криптопровайдера %1. %2'"), ИнформацияМодуляКриптографии.Имя, ОписаниеОшибки);
		Иначе
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось определить тип криптопровайдера %1'"), ИнформацияМодуляКриптографии.Имя);
		КонецЕсли;
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Если ОписаниеПрограммы.Свойство("Автоопределение") Тогда
		ОписаниеПути = Новый Структура("ПутьКПрограмме, Существует, ТекстОшибки", ОписаниеПрограммы.ПутьКПрограммеАвто, Истина, "");
	Иначе
		ОписаниеПути = ПутьКПрограмме(ОписаниеПрограммы.Ссылка);
	КонецЕсли;
	
	Если ЗначениеЗаполнено(ОписаниеПути.ТекстОшибки) Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось определить путь к программе электронной подписи
			           |""%1"" по причине:
			           |%2'"),
			ОписаниеПрограммы.Ссылка,
			ОписаниеПути.ТекстОшибки);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Свойства = Новый Структура("Тип, Путь", ОписаниеПрограммы.ТипПрограммы, "");
	Свойства.Путь = ОписаниеПути.ПутьКПрограмме;
	
	Возврат Свойства;
	
КонецФункции

Функция C14N(ОбъектКомпоненты, КонвертXML, XPath)
	
	Попытка
		КанонизированныйТекстXML = ОбъектКомпоненты.C14N(КонвертXML, XPath);
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("C14N",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если КанонизированныйТекстXML = Неопределено Тогда
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("C14N",
			ОбъектКомпоненты.ПолучитьОшибку());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат КанонизированныйТекстXML;
	
КонецФункции

Функция КанонизированныйТекстXML(ОбъектКомпоненты, ОбластьXML, Алгоритмы)
	
	Результат = Неопределено;
	ВышестоящиеПространстваИменДобавлены = Ложь;
	
	Для Каждого Алгоритм Из Алгоритмы Цикл
		Если Алгоритм.Вид = "envsig" Тогда
			Продолжить;
		ИначеЕсли Алгоритм.Вид = "c14n"
		      Или Алгоритм.Вид = "smev" Тогда
			
			Если Не ВышестоящиеПространстваИменДобавлены Тогда
				ОписаниеНачалаОбласти = ЭлектроннаяПодписьСлужебныйКлиентСервер.РасширенноеНачалоОбластиXML(
					ОбластьXML, Алгоритм, Результат);
				Если ЗначениеЗаполнено(ОписаниеНачалаОбласти.ТекстОшибки) Тогда
					ВызватьИсключение ОписаниеНачалаОбласти.ТекстОшибки;
				КонецЕсли;
				ТекстXML = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОбластиXML(ОбластьXML,
					ОписаниеНачалаОбласти.Начало);
				ВышестоящиеПространстваИменДобавлены = Истина;
				
			ИначеЕсли Результат = Неопределено Тогда
				ТекстXML = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОбластиXML(ОбластьXML);
			Иначе
				ТекстXML = Результат;
			КонецЕсли;
			
			Если Алгоритм.Вид = "c14n" Тогда
				Результат = C14N_body(ОбъектКомпоненты, ТекстXML, Алгоритм);
			Иначе
				Результат = КанонизацияСМЭВ(ОбъектКомпоненты, ТекстXML);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если Результат = Неопределено Тогда
		Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОбластиXML(ОбластьXML);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция C14N_body(ОбъектКомпоненты, ТекстXML, Алгоритм)
	
	Попытка
		КанонизированныйТекстXML = ОбъектКомпоненты.c14n_body(ТекстXML,
			Алгоритм.Версия, Алгоритм.СКомментариями);
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("C14N_body",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если КанонизированныйТекстXML = Неопределено Тогда
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("C14N_body",
			ОбъектКомпоненты.ПолучитьОшибку());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат КанонизированныйТекстXML;
	
КонецФункции

Функция КанонизацияСМЭВ(ОбъектКомпоненты, ТекстXML)
	
	Попытка
		КанонизированныйТекстXML = ОбъектКомпоненты.TransformSMEV(ТекстXML);
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("TransformSMEV",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если КанонизированныйТекстXML = Неопределено Тогда
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("TransformSMEV",
			ОбъектКомпоненты.ПолучитьОшибку());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат КанонизированныйТекстXML;
	
КонецФункции

Функция РезультатHash(ОбъектКомпоненты, КанонизированныйТекстXMLBody, OIDАлгоритмаХеширования, ТипКриптопровайдера)
	
	Попытка
		АтрибутDigestValue = ОбъектКомпоненты.Hash(
			КанонизированныйТекстXMLBody,
			OIDАлгоритмаХеширования,
			ТипКриптопровайдера);
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("Hash",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если АтрибутDigestValue = Неопределено Тогда
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("Hash",
			ОбъектКомпоненты.ПолучитьОшибку());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат АтрибутDigestValue;
	
КонецФункции

Функция РезультатSign(ОбъектКомпоненты, КанонизированныйТекстXMLSignedInfo,
	СертификатКриптографии, ПарольДоступаКЗакрытомуКлючу)
	
	СертификатКриптографииBase64 = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатКриптографииBase64(
		СертификатКриптографии.Выгрузить());
	
	Попытка
		АтрибутSignatureValue = ОбъектКомпоненты.Sign(
			КанонизированныйТекстXMLSignedInfo,
			СертификатКриптографииBase64,
			ПарольДоступаКЗакрытомуКлючу);
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("Sign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если АтрибутSignatureValue = Неопределено Тогда
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("Sign",
			ОбъектКомпоненты.ПолучитьОшибку());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат АтрибутSignatureValue;
	
КонецФункции

Функция РезультатVerifySign(ОбъектКомпоненты, КанонизированныйТекстXMLSignedInfo,
	АтрибутSignatureValue, СертификатКриптографииBase64, ТипКриптопровайдера)
	
	Попытка
		ПодписьВерна = ОбъектКомпоненты.VerifySign(
			КанонизированныйТекстXMLSignedInfo,
			АтрибутSignatureValue,
			СертификатКриптографииBase64,
			ТипКриптопровайдера);
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("VerifySign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если ПодписьВерна = Неопределено Тогда
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("VerifySign",
			ОбъектКомпоненты.ПолучитьОшибку());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат ПодписьВерна;
	
КонецФункции

Функция РезультатCMSSign(ОбъектКомпоненты, ДанныеДляПодписания, ПараметрыCMS, СертификатКриптографии, ПарольДоступаКЗакрытомуКлючу)
	
	ПараметрыКомпоненты = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПараметрыКомпонентыCMSSign(ПараметрыCMS, ДанныеДляПодписания);
	
	СертификатКриптографииBase64 = ЭлектроннаяПодписьСлужебныйКлиентСервер.СертификатКриптографииBase64(
		СертификатКриптографии.Выгрузить());
	
	Попытка
		АтрибутSignatureValue = ОбъектКомпоненты.CMSSign(
			ПараметрыКомпоненты.Данные,
			СертификатКриптографииBase64,
			ПарольДоступаКЗакрытомуКлючу,
			ПараметрыКомпоненты.ТипПодписи,
			ПараметрыКомпоненты.Открепленная,
			ПараметрыКомпоненты.ВключениеСертификатовВПодпись);
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("CMSSign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если Не ЗначениеЗаполнено(АтрибутSignatureValue) Тогда
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("CMSSign",
			ОбъектКомпоненты.ПолучитьОшибку());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	Возврат АтрибутSignatureValue;
	
КонецФункции

Функция РезультатCMSVerifySign(ОбъектКомпоненты, Подпись, Данные, ПараметрыCMS, ТипКриптопровайдера)
	
	Сертификат = Null;
	Попытка
		ПодписьВерна = ОбъектКомпоненты.CMSVerifySign(Подпись,
			ПараметрыCMS.Открепленная, Данные, ТипКриптопровайдера, Сертификат);
	Исключение
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("CMSVerifySign",
			ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение ТекстОшибки;
	КонецПопытки;
	
	Если ПодписьВерна = Неопределено Тогда
		ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОшибкаВызоваМетодаКомпоненты("CMSVerifySign",
			ОбъектКомпоненты.ПолучитьОшибку());
		ВызватьИсключение ТекстОшибки;
		
	ИначеЕсли Не ПодписьВерна Тогда
		ТекстОшибки = НСтр("ru = 'Подпись неверна.'");
		ВызватьИсключение ТекстОшибки;
		
	ИначеЕсли ТипЗнч(Сертификат) <> Тип("ДвоичныеДанные") Тогда
		ТекстОшибки = НСтр("ru = 'Подпись верна, но не содержит данных сертификата.'");
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	ДатаПодписания = ЭлектроннаяПодпись.ДатаПодписания(Подпись);
	Если Не ЗначениеЗаполнено(ДатаПодписания) Тогда
		ДатаПодписания = Неопределено;
	КонецЕсли;
	
	ВозвращаемоеЗначение = Новый Структура;
	ВозвращаемоеЗначение.Вставить("Сертификат", Новый СертификатКриптографии(Сертификат));
	ВозвращаемоеЗначение.Вставить("ДатаПодписания", ДатаПодписания);
	
	Возврат ВозвращаемоеЗначение;
	
КонецФункции


////////////////////////////////////////////////////////////////////////////////
// Вспомогательные процедуры и функции.

// Для процедуры ОбновитьСписокСертификатов.
Процедура ОбработатьДобавленныеСертификаты(ТаблицаСвойствСертификатов, КромеУжеДобавленных, ОтборПоОрганизации = Неопределено)
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Отпечатки", ТаблицаСвойствСертификатов.Скопировать(, "Отпечаток"));
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Отпечатки.Отпечаток
	|ПОМЕСТИТЬ Отпечатки
	|ИЗ
	|	&Отпечатки КАК Отпечатки
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	Сертификаты.Отпечаток,
	|	Сертификаты.Наименование КАК Представление,
	|	ЛОЖЬ КАК ЭтоЗаявление,
	|	Сертификаты.Организация
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Отпечатки КАК Отпечатки
	|		ПО Сертификаты.Отпечаток = Отпечатки.Отпечаток
	|		И &ДополнительноеСоединение";
	
	Если Метаданные.Обработки.Найти("ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата") <> Неопределено Тогда
		ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата =
			ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(
				"Обработка.ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата");
		ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата.ДополнитьЗапросПриДобавленииСертификатов(
			Запрос.Текст);
	Иначе
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "И &ДополнительноеСоединение", "");
	КонецЕсли;
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		Строка = ТаблицаСвойствСертификатов.Найти(Выборка.Отпечаток, "Отпечаток");
		Если КромеУжеДобавленных Тогда
			Если Строка <> Неопределено Тогда // Защита от ошибки в данных (дубли сертификатов).
				ТаблицаСвойствСертификатов.Удалить(Строка);
			КонецЕсли;
		ИначеЕсли ЗначениеЗаполнено(ОтборПоОрганизации) Тогда
			Если Строка <> Неопределено И Выборка.Организация <> ОтборПоОрганизации Тогда // Защита от ошибки в данных (дубли сертификатов).
				ТаблицаСвойствСертификатов.Удалить(Строка);
			КонецЕсли;
		Иначе
			Строка.Представление = Выборка.Представление;
			Строка.ЭтоЗаявление  = Выборка.ЭтоЗаявление;
			Строка.ЕстьВСправочнике = Истина;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Для процедуры ОбновитьСписокСертификатов.
Процедура ОбновитьЗначение(СтароеЗначение, НовоеЗначение, ПропускатьНеопределенныеЗначения = Ложь)
	
	Если НовоеЗначение = Неопределено И ПропускатьНеопределенныеЗначения Тогда
		Возврат;
	КонецЕсли;
	
	Если СтароеЗначение <> НовоеЗначение Тогда
		СтароеЗначение = НовоеЗначение;
	КонецЕсли;
	
КонецПроцедуры

Процедура ЗаполнитьРеквизит(СохраненныеСвойства, ПараметрыРеквизитов, ИмяРеквизита)
	
	Если ПараметрыРеквизитов.Свойство(ИмяРеквизита) Тогда
		ПараметрыРеквизита =  ПараметрыРеквизитов[ИмяРеквизита]; // Структура
		Если ПараметрыРеквизита.ЗначениеЗаполнения <> Неопределено Тогда

			СохраненныеСвойства[ИмяРеквизита] = ПараметрыРеквизита.ЗначениеЗаполнения;
			
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Для процедуры НастроитьФормуПодписанияШифрованияРасшифровки.
Процедура ЗаполнитьОтборОтпечатков(Форма)
	
	Параметры = Форма.Параметры;
	
	Отбор = Новый Соответствие;
	
	Если ТипЗнч(Параметры.СертификатыШифрования) = Тип("Массив") Тогда
		Описания = Новый Соответствие;
		Отпечатки = Новый Соответствие;
		ПредставленияОтпечатков = Новый Соответствие;
		
		ЗашифрованныеОбъекты = Новый Массив;
		
		Для Каждого Описание Из Параметры.СертификатыШифрования Цикл
			Если Описания[Описание] <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			Описания.Вставить(Описание, Истина);

			Если ТипЗнч(Описание) = Тип("Строка") Тогда
				Сертификаты = ПолучитьИзВременногоХранилища(Описание);
				Для Каждого Свойства Из Сертификаты Цикл
					Значение = Отпечатки[Свойства.Отпечаток];
					Значение = ?(Значение = Неопределено, 1, Значение + 1);
					Отпечатки.Вставить(Свойства.Отпечаток, Значение);
					ПредставленияОтпечатков.Вставить(Свойства.Отпечаток, Свойства.Представление);
				КонецЦикла;
			Иначе
				ЗашифрованныеОбъекты.Добавить(Описание);
			КонецЕсли;

		КонецЦикла;
		
		Если ЗашифрованныеОбъекты.Количество() > 0 Тогда
			Сертификаты = СертификатыШифрованияИзОписания(ЗашифрованныеОбъекты);
			Для каждого Свойства Из Сертификаты Цикл
				Значение = Отпечатки[Свойства.Отпечаток];
				Значение = ?(Значение = Неопределено, 1, Значение + 1);
				Отпечатки.Вставить(Свойства.Отпечаток, Значение);
				ПредставленияОтпечатков.Вставить(Свойства.Отпечаток, Свойства.Представление);
			КонецЦикла;
		КонецЕсли;
		
		КоличествоЭлементовДанных = Параметры.СертификатыШифрования.Количество();
		Для каждого КлючИЗначение Из Отпечатки Цикл
			Если КлючИЗначение.Значение = КоличествоЭлементовДанных Тогда
				Отбор.Вставить(КлючИЗначение.Ключ, ПредставленияОтпечатков[КлючИЗначение.Ключ]);
			КонецЕсли;
		КонецЦикла;
		
	ИначеЕсли Параметры.СертификатыШифрования <> Неопределено Тогда
		
		Сертификаты = СертификатыШифрованияИзОписания(Параметры.СертификатыШифрования);
		Для каждого Свойства Из Сертификаты Цикл
			Отбор.Вставить(Свойства.Отпечаток, Свойства.Представление);
		КонецЦикла;
	КонецЕсли;
	
	Форма.ОтборОтпечатков = ПоместитьВоВременноеХранилище(Отбор, Форма.УникальныйИдентификатор);
	
КонецПроцедуры

// Для процедуры ЗаполнитьОтборОтпечатков.
Функция СертификатыШифрованияИзОписания(Описание)
	
	Если ТипЗнч(Описание) = Тип("Строка") Тогда
		Возврат ПолучитьИзВременногоХранилища(Описание);
	КонецЕсли;
	
	Сертификаты = Новый Массив;
	
	УстановитьПривилегированныйРежим(Истина);
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	СертификатыШифрования.Представление,
		|	СертификатыШифрования.Отпечаток,
		|	СертификатыШифрования.Сертификат
		|ИЗ
		|	РегистрСведений.СертификатыШифрования КАК СертификатыШифрования
		|ГДЕ
		|	СертификатыШифрования.ЗашифрованныйОбъект В (&ЗашифрованныеОбъекты)";
		
	Если ТипЗнч(Описание) <> Тип("Массив") Тогда
		ЗашифрованныеОбъекты = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(Описание);
	Иначе
		ЗашифрованныеОбъекты = Описание;
	КонецЕсли;
	
	Запрос.УстановитьПараметр("ЗашифрованныеОбъекты", ЗашифрованныеОбъекты);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		СвойстваСертификата = Новый Структура("Отпечаток, Представление, Сертификат");
		ЗаполнитьЗначенияСвойств(СвойстваСертификата, ВыборкаДетальныеЗаписи);
		СвойстваСертификата.Сертификат = СвойстваСертификата.Сертификат.Получить();
		Сертификаты.Добавить(СвойстваСертификата);
	КонецЦикла;
	
	Возврат Сертификаты;
	
КонецФункции

Функция ДвоичныеДанныеСтроки(ДанныеСтроки)
	
	ВременныйФайл = ПолучитьИмяВременногоФайла();
	
	ЗаписьТекста = Новый ЗаписьТекста(ВременныйФайл, КодировкаТекста.UTF8);
	ЗаписьТекста.Записать(ДанныеСтроки);
	ЗаписьТекста.Закрыть();
	
	ДвоичныеДанныеСертификата = Новый ДвоичныеДанные(ВременныйФайл);
	
	УдалитьФайлы(ВременныйФайл);
	
	Возврат ДвоичныеДанныеСертификата;
	
КонецФункции

// Для процедур НастроитьФормуПодписанияШифрованияРасшифровки, СертификатПриИзмененииНаСервере.

Процедура ЗаполнитьСуществующиеСертификатыПользователя(СписокВыбора, ОтпечаткиСертификатовНаКлиенте,
			ОтборСертификатов, ОтборОтпечатков, Расшифровка, ВыполнятьНаСервере)
	
	СписокВыбора.Очистить();
	ТекущаяДатаСеанса = ?(Расшифровка И ЗначениеЗаполнено(ОтборОтпечатков), Неопределено, ТекущаяДатаСеанса());
	
	Если ЭлектроннаяПодпись.СоздаватьЭлектронныеПодписиНаСервере()
	   И ВыполнятьНаСервере <> Ложь Тогда
		
		МенеджерКриптографии = МенеджерКриптографии("ПолучениеСертификатов");
		
		Если МенеджерКриптографии <> Неопределено Тогда
			ТипХранилища = ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты;
			
			Попытка
				МассивСертификатов = МенеджерКриптографии.ПолучитьХранилищеСертификатов(ТипХранилища).ПолучитьВсе();
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьОтпечаткиСертификатов(ОтпечаткиСертификатовНаКлиенте,
					МассивСертификатов, ДобавкаВремени(), ТекущаяДатаСеанса);
			Исключение // АПК:280
				// Исключение не обрабатываем т.к. ошибка отображается в форме подбора сертификатов.
			КонецПопытки;
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Тогда
		МодульХранилищеСертификатов = ОбщегоНазначения.ОбщийМодуль("ХранилищеСертификатов");
		МассивСертификатов = МодульХранилищеСертификатов.Получить("ПерсональныеСертификаты");
		
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьОтпечаткиСертификатов(
			ОтпечаткиСертификатовНаКлиенте, МассивСертификатов, ДобавкаВремени(), ТекущаяДатаСеанса);
	КонецЕсли;
	
	Если ИспользоватьСервисОблачнойПодписи() Тогда
		
		// Локализация
		МодульСервисКриптографииDSSСлужебный = ОбщегоНазначения.ОбщийМодуль("СервисКриптографииDSSСлужебный");
		ВсеСертификаты = МодульСервисКриптографииDSSСлужебный.ПолучитьВсеСертификаты(Ложь);
		
		МассивСертификатов = Новый ТаблицаЗначений;
		МассивСертификатов.Колонки.Добавить("Отпечаток");
		МассивСертификатов.Колонки.Добавить("ДатаНачала");
		МассивСертификатов.Колонки.Добавить("ДатаОкончания");
		
		Для каждого СтрокаТаблицы Из ВсеСертификаты Цикл
			НоваяСтрока = МассивСертификатов.Добавить();
			ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаТаблицы);
			НоваяСтрока.Отпечаток = ПолучитьДвоичныеДанныеИзHexСтроки(СтрокаТаблицы.Отпечаток);
		КонецЦикла;
	
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ДобавитьОтпечаткиСертификатов(
			ОтпечаткиСертификатовНаКлиенте, МассивСертификатов, ДобавкаВремени(), ТекущаяДатаСеанса());
		// Конец Локализация
			
	КонецЕсли;	
	
	ОтборПоОрганизации = Ложь;
	
	Если ТипЗнч(ОтборСертификатов) = Тип("СписокЗначений") Тогда
		Если ОтборСертификатов.Количество() > 0 Тогда
			ТекущийСписок = Новый СписокЗначений;
			Для каждого ЭлементСписка Из ОтборСертификатов Цикл
				Свойства = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(
					ЭлементСписка.Значение, "Ссылка, Наименование, Отпечаток, Пользователь");
				
				Если ОтпечаткиСертификатовНаКлиенте.Найти(Свойства.Отпечаток) <> Неопределено Тогда
					ТекущийСписок.Добавить(Свойства.Ссылка, Свойства.Наименование,
						Свойства.Пользователь = Пользователи.АвторизованныйПользователь());
				КонецЕсли;
			КонецЦикла;
			Для Каждого ЭлементСписка Из ТекущийСписок Цикл
				Если ЭлементСписка.Пометка Тогда
					СписокВыбора.Добавить(ЭлементСписка.Значение, ЭлементСписка.Представление);
				КонецЕсли;
			КонецЦикла;
			Для Каждого ЭлементСписка Из ТекущийСписок Цикл
				Если Не ЭлементСписка.Пометка Тогда
					СписокВыбора.Добавить(ЭлементСписка.Значение, ЭлементСписка.Представление);
				КонецЕсли;
			КонецЦикла;
			Возврат;
		КонецЕсли;
	ИначеЕсли Метаданные.ОпределяемыеТипы.Организация.Тип.СодержитТип(ТипЗнч(ОтборСертификатов)) Тогда
		ОтборПоОрганизации = Истина;
	КонецЕсли;
	
	Если ОтборОтпечатков <> Неопределено Тогда
		Отбор = ПолучитьИзВременногоХранилища(ОтборОтпечатков);
		Для каждого Отпечаток Из ОтпечаткиСертификатовНаКлиенте Цикл
			Если Отбор[Отпечаток] = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			СписокВыбора.Добавить(Отпечаток, Отбор[Отпечаток]);
		КонецЦикла;
		Запрос = Новый Запрос;
		Запрос.Параметры.Вставить("Отпечатки", СписокВыбора.ВыгрузитьЗначения());
		Запрос.Текст =
		"ВЫБРАТЬ
		|	Сертификаты.Ссылка КАК Ссылка,
		|	Сертификаты.Наименование КАК Наименование,
		|	Сертификаты.Отпечаток
		|ИЗ
		|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
		|ГДЕ
		|	Сертификаты.Отпечаток В(&Отпечатки)";
		Выборка = Запрос.Выполнить().Выбрать();
		Пока Выборка.Следующий() Цикл
			ЭлементСписка = СписокВыбора.НайтиПоЗначению(Выборка.Отпечаток);
			Если ЭлементСписка <> Неопределено Тогда
				ЭлементСписка.Значение = Выборка.Ссылка;
				ЭлементСписка.Представление = Выборка.Наименование;
			КонецЕсли;
		КонецЦикла;
		СписокВыбора.СортироватьПоПредставлению();
		Возврат;
	КонецЕсли;
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	Сертификаты.Ссылка КАК Ссылка,
	|	Сертификаты.Пользователь КАК Пользователь,
	|	Сертификаты.Наименование КАК Наименование
	|ПОМЕСТИТЬ ВсеСертификаты
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК Сертификаты
	|ГДЕ
	|	Сертификаты.Отозван = ЛОЖЬ
	|	И Сертификаты.Отпечаток В(&Отпечатки)
	|	И ИСТИНА
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	ВсеСертификаты.Ссылка КАК Ссылка,
	|	ВсеСертификаты.Наименование КАК Наименование
	|ИЗ
	|	ВсеСертификаты КАК ВсеСертификаты
	|ГДЕ
	|	ВсеСертификаты.Ссылка В
	|			(ВЫБРАТЬ
	|				ВсеСертификаты.Ссылка КАК Ссылка
	|			ИЗ
	|				ВсеСертификаты КАК ВсеСертификаты
	|			ГДЕ
	|				ВсеСертификаты.Пользователь = &Пользователь
	|		
	|			ОБЪЕДИНИТЬ ВСЕ
	|		
	|			ВЫБРАТЬ
	|				ВсеСертификаты.Ссылка
	|			ИЗ
	|				ВсеСертификаты КАК ВсеСертификаты
	|					ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Пользователи КАК СертификатыКлючейЭлектроннойПодписиИШифрованияПользователи
	|					ПО
	|						ВсеСертификаты.Ссылка = СертификатыКлючейЭлектроннойПодписиИШифрованияПользователи.Ссылка
	|			ГДЕ
	|				СертификатыКлючейЭлектроннойПодписиИШифрованияПользователи.Пользователь = &Пользователь)";
	
	Если ОтборПоОрганизации Тогда
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ИСТИНА", "Сертификаты.Организация = &Организация");
	КонецЕсли;
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("Пользователь", Пользователи.ТекущийПользователь());
	Запрос.УстановитьПараметр("Отпечатки", ОтпечаткиСертификатовНаКлиенте);
	Запрос.УстановитьПараметр("Организация", ОтборСертификатов);
	
	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		СписокВыбора.Добавить(Выборка.Ссылка, Выборка.Наименование);
	КонецЦикла;
	
КонецПроцедуры

Процедура ЗаполнитьДополнительныеСвойстваСертификата(Форма)
	
	Если Не ЗначениеЗаполнено(Форма.Сертификат) Тогда
		Возврат;
	КонецЕсли;
	
	ЗначенияРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Форма.Сертификат,
		"ВводитьПарольВПрограммеЭлектроннойПодписи, Отпечаток, Программа,
		|ДействителенДо, ДанныеСертификата, Отозван");
	
	Попытка
		ДвоичныеДанныеСертификата = ЗначенияРеквизитов.ДанныеСертификата.Получить();
		Сертификат = Новый СертификатКриптографии(ДвоичныеДанныеСертификата);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		Сертификат = Форма.Сертификат;
		Форма.Сертификат = Неопределено;
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось получить данные сертификата ""%1""
			           |по причине:
			           |%2'"),
			Сертификат,
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
	КонецПопытки;
	
	ЭтоВстроенныйКриптопровайдер = ЗначенияРеквизитов.Программа = ВстроенныйКриптопровайдер();
	
	Если Форма.БезПодтверждения
	   И ЭтоВстроенныйКриптопровайдер Тогда
		
		Свойства = Новый Структура("ОблачныйПарольПодтвержден",
			ОблачныйПарольПодтвержден(ДвоичныеДанныеСертификата));
		
		ЗаполнитьЗначенияСвойств(Форма, Свойства);
	КонецЕсли;
	
	Форма.СертификатАдрес = ПоместитьВоВременноеХранилище(ДвоичныеДанныеСертификата, Форма.УникальныйИдентификатор);
	
	Форма.СертификатОтпечаток      = ЗначенияРеквизитов.Отпечаток;
	Форма.СертификатПрограмма      = ЗначенияРеквизитов.Программа;
	Форма.ВыполнятьВМоделиСервиса  = ЭтоВстроенныйКриптопровайдер;
	Форма.СертификатДействителенДо = ЗначенияРеквизитов.ДействителенДо;
	Если ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(Форма, "СертификатОтозван") Тогда
		Форма.СертификатОтозван        = ЗначенияРеквизитов.Отозван;
	КонецЕсли;
	Форма.СертификатВводитьПарольВПрограммеЭлектроннойПодписи = ЗначенияРеквизитов.ВводитьПарольВПрограммеЭлектроннойПодписи;
	
	ЕстьПараметрОповеститьОбОкончанииСрокаДействия = Форма.Параметры.Свойство("ОповеститьОбОкончанииСрокаДействия");
	Если ЕстьПараметрОповеститьОбОкончанииСрокаДействия И Форма.Параметры.ОповеститьОбОкончанииСрокаДействия 
		Или Не ЕстьПараметрОповеститьОбОкончанииСрокаДействия Тогда
		Форма.ОповеститьОбОкончанииСрокаДействия = 
			Форма.СертификатДействителенДо <= ТекущаяУниверсальнаяДата() + КоличествоДнейДляОповещенияОбОкончанииСрокаДействия()*24*60*60
			И Не РегистрыСведений.ОповещенияПользователейСертификатов.ПользовательОповещен(Форма.Сертификат)
			И Не СертификатПеревыпущен(Форма.Сертификат);
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(Форма, "РезультатПроверкиУдостоверяющегоЦентра") Тогда
		Форма.РезультатПроверкиУдостоверяющегоЦентра = РезультатПроверкиУдостоверяющегоЦентраСертификата(Сертификат);
	КонецЕсли;
	
	Форма.СертификатНаСервереОписаниеОшибки = Новый Структура;
	
	Если Не ЭлектроннаяПодпись.СоздаватьЭлектронныеПодписиНаСервере() Тогда
		Возврат;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Форма.СертификатПрограмма) Тогда
		ПрограммаПоСертификатуРезультат = ПрограммаПоСертификату(Форма.СертификатАдрес);
		Если ПрограммаПоСертификатуРезультат.Программа = Неопределено Тогда
			ТекстОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиНеУдалосьОпределитьПрограмму(
				ПрограммаПоСертификатуРезультат.Ошибка);
			Форма.СертификатНаСервереОписаниеОшибки.Вставить("ОписаниеОшибки", ТекстОшибки);
			Возврат;
		ИначеЕсли ОбщегоНазначенияКлиентСервер.ЕстьРеквизитИлиСвойствоОбъекта(Форма, "ПрограммаАвтоНаСервере") Тогда
			Форма.ПрограммаАвтоНаСервере = ПрограммаПоСертификатуРезультат.Программа;
		КонецЕсли;
		Программа = ПрограммаПоСертификатуРезультат.Программа;
	Иначе
		Программа = Форма.СертификатПрограмма;
	КонецЕсли;
	
	ПолучитьСертификатПоОтпечатку(Форма.СертификатОтпечаток,
		Истина, Ложь, Программа, Форма.СертификатНаСервереОписаниеОшибки);
	
КонецПроцедуры

Функция КоличествоДнейДляОповещенияОбОкончанииСрокаДействия()
	Возврат 30;
КонецФункции

// Для функции МенеджерКриптографии.
Функция НовыйМенеджерКриптографии(Программа, Ошибки, Автоопределение, АлгоритмПодписи = "", Операция = "")
	
	ПрограммыАвто = Неопределено;
	
	Если ТипЗнч(Программа) = Тип("Строка") Или ТипЗнч(Программа) = Тип("ДвоичныеДанные") Тогда
		
		ОписаниеОшибки = "";
		ТребуетсяЗакрытыйКлюч = Операция = "Подписание"
			Или Операция = "Расшифровка";
		ЗаполнитьПараметрыДляСозданияМенеджераКриптографии(Программа, АлгоритмПодписи, ОписаниеОшибки, ТребуетсяЗакрытыйКлюч);
		
		Если ЗначениеЗаполнено(ОписаниеОшибки) Тогда
			СвойстваОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеСвойстваОшибки();
			СвойстваОшибки.Описание = ОписаниеОшибки;
			Ошибки.Добавить(СвойстваОшибки);
			
			Если Программа = Неопределено И ТребуетсяЗакрытыйКлюч Тогда
				Возврат Неопределено;
			КонецЕсли;
		КонецЕсли;
		
	КонецЕсли;
	
	Если Автоопределение И ТипЗнч(Программа) <> Тип("Структура") И ТипЗнч(Программа) <> Тип("ФиксированнаяСтруктура") Тогда
		
		КриптопровайдерыРезультат = ЭлектроннаяПодписьСлужебныйПовтИсп.УстановленныеКриптопровайдеры();
		ПрограммыАвто = ЭлектроннаяПодписьСлужебныйКлиентСервер.РезультатПоискаКриптопровайдеров(
			КриптопровайдерыРезультат, ИмяКомпьютера());
		
		Если ТипЗнч(ПрограммыАвто) = Тип("Строка") Тогда
			СвойстваОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыеСвойстваОшибки();
			СвойстваОшибки.Описание = ПрограммыАвто;
			Ошибки.Добавить(СвойстваОшибки);
			ПрограммыАвто = Неопределено;
		КонецЕсли;
	
	КонецЕсли;
	
	ОписанияПрограмм = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииОписанияПрограмм(
		Программа, Ошибки, ЭлектроннаяПодпись.ОбщиеНастройки().ОписанияПрограмм, ПрограммыАвто);
	
	Если ОписанияПрограмм = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ЭтоLinux = ТребуетсяПутьКПрограмме();
	
	Менеджер = Неопределено;
	Для Каждого ОписаниеПрограммы Из ОписанияПрограмм Цикл
		
		Если ЗначениеЗаполнено(АлгоритмПодписи) Тогда
			АлгоритмПодписиПоддерживается =
				ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииАлгоритмПодписиПоддерживается(ОписаниеПрограммы,
					Операция, АлгоритмПодписи, Ошибки, Истина, Программа <> Неопределено);
			
			Если Не АлгоритмПодписиПоддерживается Тогда
				Менеджер = Неопределено;
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		Если ОписаниеПрограммы.Свойство("Автоопределение") Тогда
			
			СвойстваПрограммы = Новый Структура;
			СвойстваПрограммы.Вставить("ИмяПрограммы",   ОписаниеПрограммы.ИмяПрограммы);
			СвойстваПрограммы.Вставить("ПутьКПрограмме", ОписаниеПрограммы.ПутьКПрограммеНаСервереАвто);
			СвойстваПрограммы.Вставить("ТипПрограммы",   ОписаниеПрограммы.ТипПрограммы);
			
		Иначе

			ИдентификаторПутиКПрограмме = ?(ЗначениеЗаполнено(ОписаниеПрограммы.Ссылка),
				ОписаниеПрограммы.Ссылка, ОписаниеПрограммы.Идентификатор);
		
			СвойстваПрограммы = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииСвойстваПрограммы(
				ОписаниеПрограммы, ЭтоLinux, Ошибки, Истина, ПутьКПрограмме(ИдентификаторПутиКПрограмме));

		КонецЕсли;
		
		Если СвойстваПрограммы = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		Попытка
			ИнформацияМодуля = СредстваКриптографии.ПолучитьИнформациюМодуляКриптографии(
				СвойстваПрограммы.ИмяПрограммы,
				СвойстваПрограммы.ПутьКПрограмме,
				СвойстваПрограммы.ТипПрограммы);
		Исключение
			ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииДобавитьОшибку(Ошибки,
				ОписаниеПрограммы.Ссылка, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()),
				Истина, Истина, Истина);
			Продолжить;
		КонецПопытки;
		
		Если ИнформацияМодуля = Неопределено Тогда
			ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииПрограммаНеНайдена(
				ОписаниеПрограммы, Ошибки, Истина);
			
			Менеджер = Неопределено;
			Продолжить;
		КонецЕсли;
		
		Если Не ЭтоLinux Тогда
			ИмяПрограммыПолученное = ИнформацияМодуля.Имя;
			
			ИмяПрограммыСовпадает = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииИмяПрограммыСовпадает(
				ОписаниеПрограммы, ИмяПрограммыПолученное, Ошибки, Истина);
			
			Если Не ИмяПрограммыСовпадает Тогда
				Менеджер = Неопределено;
				Продолжить;
			КонецЕсли;
		КонецЕсли;
		
		Попытка
			Менеджер = Новый МенеджерКриптографии(
				СвойстваПрограммы.ИмяПрограммы,
				СвойстваПрограммы.ПутьКПрограмме,
				СвойстваПрограммы.ТипПрограммы);
		Исключение
			ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииДобавитьОшибку(Ошибки,
				ОписаниеПрограммы.Ссылка, ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()),
				Истина, Истина, Истина);
			Продолжить;
		КонецПопытки;
		
		АлгоритмыУстановлены = ЭлектроннаяПодписьСлужебныйКлиентСервер.МенеджерКриптографииАлгоритмыУстановлены(
			ОписаниеПрограммы, Менеджер, Ошибки);
		
		Если Не АлгоритмыУстановлены Тогда
			Продолжить;
		КонецЕсли;
		
		Прервать; // Требуемый менеджер криптографии получен.
	КонецЦикла;
	
	Возврат Менеджер;
	
КонецФункции

// Для функции НовыйМенеджерКриптографии.
Процедура ЗаполнитьПараметрыДляСозданияМенеджераКриптографии(Программа, АлгоритмПодписи, ОписаниеОшибки, ТребуетсяЗакрытыйКлюч)
	
	Данные = Программа;
	
	Попытка
		
		ТипДанных = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОпределитьТипДанных(Данные);
		
	Исключение
		
		Программа = Неопределено;
		ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ВставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось определить программу для переданных данных: %1'"),
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат;
	КонецПопытки;
	
	Если ТипДанных = "Сертификат" Тогда
		
		ПрограммаПоСертификатуРезультат = ПрограммаПоСертификату(Данные, ТребуетсяЗакрытыйКлюч);
		Если ЗначениеЗаполнено(ПрограммаПоСертификатуРезультат.Ошибка) Тогда
			
			ОписаниеОшибки = ЭлектроннаяПодписьСлужебныйКлиентСервер.ТекстОшибкиНеУдалосьОпределитьПрограмму(
				ПрограммаПоСертификатуРезультат.Ошибка);
			АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмПодписиСертификата(Данные);
			Программа = Неопределено;
			
		Иначе
			Программа = ПрограммаПоСертификатуРезультат.Программа;
		КонецЕсли;
		
		Возврат;
		
	ИначеЕсли ТипДанных = "Подпись" Тогда
		
		Программа = Неопределено;
		АлгоритмПодписи = ЭлектроннаяПодписьСлужебныйКлиентСервер.АлгоритмСформированнойПодписи(Данные);
		Возврат;
		
	ИначеЕсли ТипДанных = "ЗашифрованныеДанные" Тогда
		
		Программа = Неопределено;
		ОписаниеОшибки = НСтр("ru = 'Для определения программы для расшифровки в процедуру должны быть переданы данные сертификата.'");
		Возврат;
		
	КонецЕсли;
	
	Программа = Неопределено;
	ОписаниеОшибки = НСтр("ru = 'Не удалось определить программу для переданных данных.'");
	
КонецПроцедуры

Функция ПрограммаПоСертификату(Знач Сертификат, ТребуетсяЗакрытыйКлюч = Неопределено,  ОбъектКомпоненты = Неопределено) Экспорт

	Результат = Новый Структура("Программа, Ошибка");

	Сертификат = СертификатBase64Строка(Сертификат);

	Если ОбъектКомпоненты = Неопределено Тогда
		Попытка
			ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
		Исключение
			Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось подключить компоненту %1 на сервере %2.'"), "ExtraCryptoAPI", ИмяКомпьютера());
			Возврат Результат;
		КонецПопытки;
	КонецЕсли;
	
	Если ТребуетсяЗакрытыйКлюч <> Ложь Тогда
		
		Попытка
			СвойстваКриптопровайдера = ОбъектКомпоненты.ПолучитьСвойстваКриптопровайдера(Сертификат);
			ТекущийКриптопровайдер = ЭлектроннаяПодписьСлужебныйВызовСервера.ПрочитатьОтветКомпоненты(
				СвойстваКриптопровайдера);
		Исключение
			Результат.Ошибка = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
			Возврат Результат;
		КонецПопытки;
		
		ПрограммыПоИменамСТипом = ЭлектроннаяПодпись.ОбщиеНастройки().ПрограммыПоИменамСТипом;
		РасширенноеОписаниеПрограммы = ЭлектроннаяПодписьСлужебныйКлиентСервер.РасширенноеОписаниеПрограммы(
			ТекущийКриптопровайдер, ПрограммыПоИменамСТипом);
		
		Если РасширенноеОписаниеПрограммы <> Неопределено Тогда
			Результат.Программа = РасширенноеОписаниеПрограммы;
			Возврат Результат;
		ИначеЕсли ТребуетсяЗакрытыйКлюч = Истина И ТекущийКриптопровайдер.Получить("type") <> 0 Тогда
			Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Сертификат связан с программой %1 с типом %2 на сервере %3, настройте ее для использования и выберите в сертификате.'"),
				ТекущийКриптопровайдер.Получить("name"),
				ТекущийКриптопровайдер.Получить("type"), ИмяКомпьютера());
			Возврат Результат;
		КонецЕсли;
		
	КонецЕсли;
	
	Если ТребуетсяЗакрытыйКлюч = Истина Тогда
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось определить программу по закрытому ключу сертификата на сервере %1.'"), ИмяКомпьютера());
		Возврат Результат;
	КонецЕсли;
		
	СвойстваСертификатаРасширенные = СвойстваСертификатаРасширенные(Сертификат, ОбъектКомпоненты);
	РезультатКриптопровайдеры = ЭлектроннаяПодписьСлужебныйПовтИсп.УстановленныеКриптопровайдеры();
	
	Если РезультатКриптопровайдеры.ПроверкаВыполнена Тогда
		
		Ошибка = "";
		
		Результат.Программа = ЭлектроннаяПодписьСлужебныйКлиентСервер.ОпределитьПрограмму(
			СвойстваСертификатаРасширенные.СвойстваСертификата, РезультатКриптопровайдеры.Криптопровайдеры,
			ЭлектроннаяПодпись.ОбщиеНастройки().ПрограммыПоИдентификаторамАлгоритмовОткрытогоКлюча, Ошибка);
	
		Если Результат.Программа = Неопределено Тогда
			Результат.Ошибка = Ошибка;
		КонецЕсли;
	
		Возврат Результат;
	Иначе
		Результат.Ошибка = РезультатКриптопровайдеры.Ошибка;
		Возврат Результат;
	КонецЕсли;
	
КонецФункции

Функция ИспользоватьЭлектроннуюПодписьВМоделиСервиса() Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.ЭлектроннаяПодписьВМоделиСервиса") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	МодульЭлектроннаяПодписьВМоделиСервиса =
		ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьВМоделиСервиса");
	
	Возврат МодульЭлектроннаяПодписьВМоделиСервиса.ИспользованиеВозможно();
	
КонецФункции

Функция ПутьКПрограмме(ПрограммаСсылка)
	
	Результат = Новый Структура("ПутьКПрограмме, Существует, ТекстОшибки", "", Ложь, "");
	
	Если Не ТребуетсяПутьКПрограмме() Тогда
		Возврат Результат;
	КонецЕсли;
	
	ПутиКПрограммам = ЭлектроннаяПодписьСлужебныйПовтИсп.ПутиКПрограммамНаСерверахLinux(ИмяКомпьютера());
	ОписаниеПути = ПутиКПрограммам.Получить(ПрограммаСсылка);
	
	Если ОписаниеПути <> Неопределено Тогда
		Результат = ОписаниеПути;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Для функции ПолучитьСоответствиеФайловИПодписей.
Функция НайтиИменаФайловПодписей(ИмяФайлаДанных, ИменаФайловПодписей)
	
	ИменаПодписей = Новый Массив;
	
	СтруктураИмени = ОбщегоНазначенияКлиентСервер.РазложитьПолноеИмяФайла(ИмяФайлаДанных);
	ИмяБезРасширения = СтруктураИмени.ИмяБезРасширения;
	
	Для Каждого ИмяФайлаПодписи Из ИменаФайловПодписей Цикл
		Если СтрНайти(ИмяФайлаПодписи, ИмяБезРасширения) > 0 Тогда
			ИменаПодписей.Добавить(ИмяФайлаПодписи);
		КонецЕсли;
	КонецЦикла;
	
	Для Каждого ИмяФайлаПодписи Из ИменаПодписей Цикл
		ИменаФайловПодписей.Удалить(ИменаФайловПодписей.Найти(ИмяФайлаПодписи));
	КонецЦикла;
	
	Возврат ИменаПодписей;
	
КонецФункции

// Для процедуры ЗаписатьСертификатПослеПроверки.

Функция ПроверитьШифрованиеИРасшифровку(МенеджерКриптографии, ДвоичныеДанныеСертификата,
			СертификатКриптографии, ОписаниеПрограммы, ОшибкаНаСервере, ЭтоПолноправныйПользователь)
	
	ПредставлениеОшибки = "";
	Попытка
		ЗашифрованныеДанные = МенеджерКриптографии.Зашифровать(ДвоичныеДанныеСертификата, СертификатКриптографии);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	КонецПопытки;
	
	Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаполнитьОшибкуДобавленияСертификата(
			ОшибкаНаСервере,
			ОписаниеПрограммы,
			"Шифрование",
			ПредставлениеОшибки,
			ЭтоПолноправныйПользователь,
			Ложь,
			ИмяКомпьютера());
		
		Возврат Ложь;
	КонецЕсли;
	
	ИнформацияОбОшибке = Неопределено;
	ПредставлениеОшибки = "";
	Попытка
		РасшифрованныеДанные = МенеджерКриптографии.Расшифровать(ЗашифрованныеДанные);
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеРасшифрованныеДанные(РасшифрованныеДанные, ПредставлениеОшибки);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	КонецПопытки;
	
	Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаполнитьОшибкуДобавленияСертификата(
			ОшибкаНаСервере,
			ОписаниеПрограммы,
			"Расшифровка",
			ПредставлениеОшибки,
			ЭтоПолноправныйПользователь,
			ИнформацияОбОшибке = Неопределено,
			ИмяКомпьютера());
		
		Возврат Ложь;
	КонецЕсли;
		
	Возврат Истина;
	
КонецФункции

Функция ПроверитьПодписание(МенеджерКриптографии, ДвоичныеДанныеСертификата,
			СертификатКриптографии, ОписаниеПрограммы, ОшибкаНаСервере, ЭтоПолноправныйПользователь)
	
	ИнформацияОбОшибке = Неопределено;
	ПредставлениеОшибки = "";
	Попытка
		ДанныеПодписи = МенеджерКриптографии.Подписать(ДвоичныеДанныеСертификата, СертификатКриптографии);
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПустыеДанныеПодписи(ДанныеПодписи, ПредставлениеОшибки);
	Исключение
		ИнформацияОбОшибке = ИнформацияОбОшибке();
		ПредставлениеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
	КонецПопытки;
	
	Если ЗначениеЗаполнено(ПредставлениеОшибки) Тогда
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ЗаполнитьОшибкуДобавленияСертификата(
			ОшибкаНаСервере,
			ОписаниеПрограммы,
			"Подписание",
			ПредставлениеОшибки,
			ЭтоПолноправныйПользователь,
			ИнформацияОбОшибке = Неопределено,
			ИмяКомпьютера());
		
		Возврат Ложь;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

// Возвращаемое значение:
//   ТаблицаЗначений:
//     * АлгоритмыПодписи     - Массив
//     * АлгоритмыХеширования - Массив
//     * АлгоритмыШифрования  - Массив
//     * АлгоритмыПроверкиПодписи - Массив
//     * НетВWindows - Булево
//     * НетВLinux   - Булево
//     * НетВMacOS   - Булево
//
Функция ПоставляемыеНастройкиПрограмм() Экспорт
	
	Настройки = Новый ТаблицаЗначений;
	Настройки.Колонки.Добавить("Представление");
	Настройки.Колонки.Добавить("ИмяПрограммы");
	Настройки.Колонки.Добавить("ТипПрограммы");
	Настройки.Колонки.Добавить("АлгоритмПодписи");
	Настройки.Колонки.Добавить("АлгоритмХеширования");
	Настройки.Колонки.Добавить("АлгоритмШифрования");
	Настройки.Колонки.Добавить("Идентификатор");
	
	Настройки.Колонки.Добавить("АлгоритмыПодписи",     Новый ОписаниеТипов("Массив"));
	Настройки.Колонки.Добавить("АлгоритмыХеширования", Новый ОписаниеТипов("Массив"));
	Настройки.Колонки.Добавить("АлгоритмыШифрования",  Новый ОписаниеТипов("Массив"));
	Настройки.Колонки.Добавить("АлгоритмыПроверкиПодписи", Новый ОписаниеТипов("Массив"));
	Настройки.Колонки.Добавить("НетВWindows", Новый ОписаниеТипов("Булево"));
	Настройки.Колонки.Добавить("НетВLinux",   Новый ОписаниеТипов("Булево"));
	Настройки.Колонки.Добавить("НетВMacOS",   Новый ОписаниеТипов("Булево"));
	
	Возврат Настройки;
	
КонецФункции

// Возвращаемое значение:
//   Структура:
//     * Ключ - Строка - начало идентификатора программы, например, CryptoPro.
//     * Значение - ФиксированноеСоответствие из КлючИЗначение:
//         * Ключ - ТипПлатформы
//         * Значение - ФиксированныйМассив из Строка - пути
//             с именами модулей, разделенные символом двоеточие.
//
Функция ПоставляемыеПутиКМодулямПрограмм() Экспорт
	
	Возврат Новый Структура;
	
КонецФункции

// Вызывается при переходе на версию конфигурации 3.1.6.128 и при начальном заполнении.
// 
Процедура ЗаполнитьНастройкиДляУсовершенствованияПодписей() Экспорт
	
	МенеджерЗначения = Константы.ТипПодписиКриптографииПоУмолчанию.СоздатьМенеджерЗначения();
	МенеджерЗначения.Значение = Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES;
	ОбновлениеИнформационнойБазы.ЗаписатьДанные(МенеджерЗначения);

	ЗаполнитьАдресаСерверовМетокВремени();
	
КонецПроцедуры

// Вызывается при переходе на версию конфигурации 3.1.6.180 
// и из процедуры ЗаполнитьНастройкиДляУсовершенствованияПодписей
// 
Процедура ЗаполнитьАдресаСерверовМетокВремени() Экспорт

	Если Метаданные.Обработки.Найти("ПрограммыЭлектроннойПодписиИШифрования") <> Неопределено Тогда
		АдресаСерверовМетокВремени = Обработки["ПрограммыЭлектроннойПодписиИШифрования"].АдресаСерверовМетокВремениДляНачальногоЗаполнения();
		Если Не ПустаяСтрока(АдресаСерверовМетокВремени) Тогда
			МенеджерЗначения = Константы.АдресаСерверовМетокВремени.СоздатьМенеджерЗначения();
			МенеджерЗначения.Значение = АдресаСерверовМетокВремени;
			ОбновлениеИнформационнойБазы.ЗаписатьДанные(МенеджерЗначения);
		КонецЕсли;
	КонецЕсли;

КонецПроцедуры

Функция СертификатПеревыпущен(Сертификат)
	
	Если ЭлектроннаяПодпись.ОбщиеНастройки().ЗаявлениеНаВыпускСертификатаДоступно Тогда
		ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата =
			ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(
				"Обработка.ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата");
		ВыпущенныеСертификаты = ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата.ВыпущенныеСертификаты(Сертификат);
		Если ВыпущенныеСертификаты.Количество() > 0 Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция КоличествоСертификатовСИстекающимСрокомДействия()

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	СертификатыКлючейЭлектроннойПодписиИШифрования.Ссылка
	|ПОМЕСТИТЬ СертификатыПользователя
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК СертификатыКлючейЭлектроннойПодписиИШифрования
	|ГДЕ
	|	СертификатыКлючейЭлектроннойПодписиИШифрования.Пользователь = &Пользователь
	|
	|ОБЪЕДИНИТЬ ВСЕ
	|
	|ВЫБРАТЬ
	|	СертификатыКлючейЭлектроннойПодписиИШифрованияПользователи.Ссылка
	|ИЗ
	|	Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования.Пользователи КАК
	|		СертификатыКлючейЭлектроннойПодписиИШифрованияПользователи
	|ГДЕ
	|	СертификатыКлючейЭлектроннойПодписиИШифрованияПользователи.Пользователь = &Пользователь
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	КОЛИЧЕСТВО(РАЗЛИЧНЫЕ СертификатыКлючейЭлектроннойПодписиИШифрования.Ссылка) КАК Количество
	|ИЗ
	|	СертификатыПользователя КАК СертификатыПользователя
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.СертификатыКлючейЭлектроннойПодписиИШифрования КАК
	|			СертификатыКлючейЭлектроннойПодписиИШифрования
	|		ПО СертификатыПользователя.Ссылка = СертификатыКлючейЭлектроннойПодписиИШифрования.Ссылка
	|ГДЕ
	|	НЕ СертификатыКлючейЭлектроннойПодписиИШифрования.ПометкаУдаления
	|	И СертификатыКлючейЭлектроннойПодписиИШифрования.ДействителенДо >= &ТекущаяДата
	|	И СертификатыКлючейЭлектроннойПодписиИШифрования.ДействителенДо <= &Дата
	|	И НЕ СертификатыКлючейЭлектроннойПодписиИШифрования.Отозван";

	ТекущаяДата = ТекущаяУниверсальнаяДата();
	Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДата);
	Запрос.УстановитьПараметр("Дата", ТекущаяДата + 30*24*60*60);
	Запрос.УстановитьПараметр("Пользователь", Пользователи.ТекущийПользователь());
	
	Возврат Запрос.Выполнить().Выгрузить()[0].Количество;
	
КонецФункции

Функция КоличествоЗаявленийВРаботе()
	
	ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата =
			ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(
				"Обработка.ЗаявлениеНаВыпускНовогоКвалифицированногоСертификата");
				
	Возврат ОбработкаЗаявлениеНаВыпускНовогоКвалифицированногоСертификата.КоличествоЗаявленийВРаботе();
	
КонецФункции

Функция КоличествоПодписей(Параметр) Экспорт
	
	ПараметрыЗапроса = Новый Структура;
	ПараметрыЗапроса.Вставить(Параметр, Истина);
	ПараметрыЗапроса.Вставить("ТолькоКоличество", Истина);
	
	Запрос = ЗапросДляПродленияДостоверностиПодписей(ПараметрыЗапроса);
		
	Если Запрос = Неопределено Тогда
		Возврат 0;
	КонецЕсли;
	
	УстановитьПривилегированныйРежим(Истина);
	РезультатЗапроса = Запрос.Выполнить();
	УстановитьПривилегированныйРежим(Ложь);
	Возврат РезультатЗапроса.Выгрузить()[0].Количество;
	
КонецФункции

Функция ЗапросДляПродленияДостоверностиПодписей(Параметры) Экспорт
	
	ПараметрыЗапроса = Новый Структура;
	ПараметрыЗапроса.Вставить("ТребуетсяУсовершенствоватьПодписи", Ложь);
	ПараметрыЗапроса.Вставить("ТребуетсяДобавитьАрхивныеМетки", Ложь);
	ПараметрыЗапроса.Вставить("НеобработанныеПодписи", Ложь);
	ПараметрыЗапроса.Вставить("ОшибкиПриАвтоматическомПродлении", Ложь);
	ПараметрыЗапроса.Вставить("ТолькоКоличество", Ложь);
	ПараметрыЗапроса.Вставить("УсовершенствоватьДоТипа", Неопределено);
	ПараметрыЗапроса.Вставить("РегламентноеЗадание", Ложь);
	
	ЗаполнитьЗначенияСвойств(ПараметрыЗапроса, Параметры);
	
	Запрос = Новый Запрос;
	ТекстЗапроса = "";
	
	УсовершенствоватьПодписиСДаты = Константы.УсовершенствоватьПодписиСДаты.Получить();
	
	Если ПараметрыЗапроса.ТребуетсяУсовершенствоватьПодписи Тогда
		
		ТекстЗапроса =
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*) КАК Количество
		|ИЗ
		|	РегистрСведений.ЭлектронныеПодписи КАК ЭлектронныеПодписи
		|ГДЕ
		|	ЭлектронныеПодписи.ТипПодписи В(&ТипПодписи)
		|	И ЭлектронныеПодписи.ПодписьВерна
		|	И НЕ ЭлектронныеПодписи.ОшибкаПриАвтоматическомПродлении
		|	И НЕ ЭлектронныеПодписи.ПропуститьПриПродлении
		|	И (ЭлектронныеПодписи.СрокДействияПоследнейМеткиВремени = ДАТАВРЕМЯ(1, 1, 1)
		|			ИЛИ ЭлектронныеПодписи.СрокДействияПоследнейМеткиВремени > &ТекущаяДатаСеанса)
		|	И ЭлектронныеПодписи.ДатаПодписи >= &УсовершенствоватьПодписиСДаты";

		Запрос.УстановитьПараметр("ТекущаяДатаСеанса", ТекущаяДатаСеанса());
		Запрос.УстановитьПараметр("УсовершенствоватьПодписиСДаты", УсовершенствоватьПодписиСДаты);
		
		УсовершенствоватьДоТипа = ПараметрыЗапроса.УсовершенствоватьДоТипа;
		Если УсовершенствоватьДоТипа = Неопределено Тогда
			УсовершенствоватьДоТипа = Константы.ТипПодписиКриптографииПоУмолчанию.Получить();
		КонецЕсли;
		
		ТипПодписи = Новый Массив;
		Если УсовершенствоватьДоТипа = Перечисления.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST Тогда
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES);
		ИначеЕсли УсовершенствоватьДоТипа = Перечисления.ТипыПодписиКриптографии.АрхивнаяCAdESAv3 Тогда
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.БазоваяCAdESBES);
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.СМеткойДоверенногоВремениCAdEST);
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.СПолнымНаборомПроверочныхДанныхCAdESC);
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.CAdESXType1);
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.CAdESXType2);
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.CAdESXLong);
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.CAdESXLongType1);
			ТипПодписи.Добавить(Перечисления.ТипыПодписиКриптографии.РасширеннаяДолгосрочнаяCAdESXLongType2);
		Иначе
			ТекстЗапроса = "";
		КонецЕсли;
		Запрос.УстановитьПараметр("ТипПодписи", ТипПодписи);
		
	КонецЕсли;
	
	Если ПараметрыЗапроса.ТребуетсяДобавитьАрхивныеМетки Тогда
	
		ТекстЗапроса = ?(ТекстЗапроса = "", "", ТекстЗапроса + "
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|")
		+
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*) КАК Количество
		|ИЗ
		|	РегистрСведений.ЭлектронныеПодписи КАК ЭлектронныеПодписи
		|ГДЕ
		|	ЭлектронныеПодписи.ТипПодписи = ЗНАЧЕНИЕ(Перечисление.ТипыПодписиКриптографии.АрхивнаяCAdESAv3)
		|	И ЭлектронныеПодписи.СрокДействияПоследнейМеткиВремени <= &Дата
		|	И НЕ ЭлектронныеПодписи.ОшибкаПриАвтоматическомПродлении
		|	И НЕ ЭлектронныеПодписи.ПропуститьПриПродлении
		|	И ЭлектронныеПодписи.ПодписьВерна
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*)
		|ИЗ
		|	РегистрСведений.ЭлектронныеПодписи КАК ЭлектронныеПодписи
		|ГДЕ
		|	ЭлектронныеПодписи.ТипПодписи = ЗНАЧЕНИЕ(Перечисление.ТипыПодписиКриптографии.CAdESAv2)
		|	И ЭлектронныеПодписи.СрокДействияПоследнейМеткиВремени <= &Дата
		|	И НЕ ЭлектронныеПодписи.ОшибкаПриАвтоматическомПродлении
		|	И НЕ ЭлектронныеПодписи.ПропуститьПриПродлении
		|	И ЭлектронныеПодписи.ПодписьВерна";
		
		Запрос.УстановитьПараметр("Дата", ДобавитьМесяц(ТекущаяДатаСеанса(), 1));
		
	КонецЕсли; 
	
	Если ПараметрыЗапроса.НеобработанныеПодписи Тогда
		
		ТекстЗапроса = ?(ТекстЗапроса = "", "", ТекстЗапроса + "
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|")
		+
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*) КАК Количество
		|ИЗ
		|	РегистрСведений.ЭлектронныеПодписи КАК ЭлектронныеПодписи
		|ГДЕ
		|	ЭлектронныеПодписи.ТипПодписи = ЗНАЧЕНИЕ(Перечисление.ТипыПодписиКриптографии.ПустаяСсылка)
		|	И ЭлектронныеПодписи.ПодписьВерна
		|	И НЕ ЭлектронныеПодписи.ОшибкаПриАвтоматическомПродлении
		|	И НЕ ЭлектронныеПодписи.ПропуститьПриПродлении
		|	И (ЭлектронныеПодписи.СрокДействияПоследнейМеткиВремени = ДАТАВРЕМЯ(1, 1, 1)
		|			ИЛИ ЭлектронныеПодписи.СрокДействияПоследнейМеткиВремени > &ТекущаяДатаСеанса)
		|	И ЭлектронныеПодписи.ДатаПодписи >= &УсовершенствоватьПодписиСДаты";
		
		Запрос.УстановитьПараметр("ТекущаяДатаСеанса", ТекущаяДатаСеанса());
		Запрос.УстановитьПараметр("УсовершенствоватьПодписиСДаты", УсовершенствоватьПодписиСДаты);
		
	КонецЕсли;
	
	Если ПараметрыЗапроса.ОшибкиПриАвтоматическомПродлении Тогда
		
		ТекстЗапроса = ?(ТекстЗапроса = "", "", ТекстЗапроса + "
		|
		|ОБЪЕДИНИТЬ ВСЕ
		|
		|")
		+
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*) КАК Количество
		|ИЗ
		|	РегистрСведений.ЭлектронныеПодписи КАК ЭлектронныеПодписи
		|ГДЕ
		|	ЭлектронныеПодписи.ОшибкаПриАвтоматическомПродлении";
		
	КонецЕсли;
	
	Если ПустаяСтрока(ТекстЗапроса) Тогда
		ТекстЗапроса = 
		"ВЫБРАТЬ
		|	КОЛИЧЕСТВО(*) КАК Количество
		|ИЗ
		|	РегистрСведений.ЭлектронныеПодписи КАК ЭлектронныеПодписи
		|ГДЕ
		|	ЛОЖЬ"
	КонецЕсли;
	
	Если Не ПараметрыЗапроса.ТолькоКоличество Тогда
		
		СтрокаПоиска = "КОЛИЧЕСТВО(*) КАК Количество";
		СтрокаЗамены = "ЭлектронныеПодписи.ПодписанныйОбъект КАК ПодписанныйОбъект,
		|	ЭлектронныеПодписи.ПорядковыйНомер КАК ПорядковыйНомер,
		|	ЭлектронныеПодписи.ДатаПодписи КАК ДатаПодписи,
		|	ЭлектронныеПодписи.КомуВыданСертификат КАК КомуВыданСертификат,
		|	ЭлектронныеПодписи.ТипПодписи КАК ТипПодписи,
		|	ЭлектронныеПодписи.ОшибкаПриАвтоматическомПродлении КАК ОшибкаПриАвтоматическомПродлении,
		|	ЭлектронныеПодписи.СрокДействияПоследнейМеткиВремени КАК СрокДействияПоследнейМеткиВремени";
		
		Если ПараметрыЗапроса.РегламентноеЗадание Тогда
			СтрокаЗамены = СтрокаЗамены +",
			|	ЭлектронныеПодписи.Подпись КАК Подпись";
		КонецЕсли;
		
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, СтрокаПоиска, СтрокаЗамены);
		
		СтрокаПоиска = "КОЛИЧЕСТВО(*)";
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, СтрокаПоиска, СтрокаЗамены);
		
		Если ПараметрыЗапроса.РегламентноеЗадание Тогда
			ТекстЗапроса = ТекстЗапроса + "
						|УПОРЯДОЧИТЬ ПО
						|	ДатаПодписи
						|";
		КонецЕсли;

	КонецЕсли;
	
	Если ПараметрыЗапроса.РегламентноеЗадание Тогда
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "ВЫБРАТЬ", "ВЫБРАТЬ ПЕРВЫЕ 1000"); // @query-part-1 @query-part-2
	Иначе
		ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "И НЕ ЭлектронныеПодписи.ОшибкаПриАвтоматическомПродлении", "");
	КонецЕсли;
	
	Запрос.Текст = ТекстЗапроса;
	
	Возврат Запрос;
	
КонецФункции

// Производит поиск физических лиц по наименованию
// 
// Параметры:
//   КомуВыдан - Массив из Строка
//             - Строка
//
// Возвращаемое значение:
//   Соответствие из КлючИЗначение:
//     * Ключ     - Строка - наименование физического лица
//     * Значение - Массив из ОпределяемыйТип.ФизическоеЛицо - ссылки на справочник физические лица, указанный в
//                                                             определяемом типе ФизическоеЛицо
//
Функция ПолучитьФизическиеЛицаПоПолюСертификатаКомуВыдан(КомуВыдан) Экспорт

	ФизическиеЛицаПоФИО = Новый Соответствие;

	ТипыФизическоеЛицо = Метаданные.ОпределяемыеТипы.ФизическоеЛицо.Тип.Типы();
	Если ТипыФизическоеЛицо[0] <> Тип("Строка") Тогда
		ФизическоеЛицоПустаяСсылка = Новый (ТипыФизическоеЛицо[0]);
	Иначе
		Возврат ФизическиеЛицаПоФИО;	
	КонецЕсли;
	
	ФизическоеЛицоИмяМетаданных = ОбщегоНазначения.ИмяТаблицыПоСсылке(ФизическоеЛицоПустаяСсылка);
	
	Запрос = Новый Запрос;
	ТекстЗапроса = 
	"ВЫБРАТЬ
	|	ФизическиеЛица.Ссылка КАК Ссылка,
	|	ФизическиеЛица.Наименование КАК Наименование
	|ИЗ
	|	Справочник.Пользователи КАК ФизическиеЛица
	|ГДЕ
	|	ФизическиеЛица.Наименование В(&КомуВыдан)
	|ИТОГИ ПО
	|	Наименование";
	
	ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "Справочник.Пользователи", ФизическоеЛицоИмяМетаданных);
		
	Запрос.УстановитьПараметр("КомуВыдан", КомуВыдан);
	
	Запрос.Текст = ТекстЗапроса;
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаНаименование = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
	
	Пока ВыборкаНаименование.Следующий() Цикл
		
		Выборка = ВыборкаНаименование.Выбрать();
		ФизическиеЛица = Новый Массив;
		
		Пока Выборка.Следующий() Цикл
			ФизическиеЛица.Добавить(Выборка.Ссылка);
		КонецЦикла;
		
		ФизическиеЛицаПоФИО.Вставить(ВыборкаНаименование.Наименование, ФизическиеЛица); 

	КонецЦикла;
	
	Возврат ФизическиеЛицаПоФИО;
	
КонецФункции

// Для процедуры НастроитьФормуОбщихНастроек.
Процедура УстановитьЗаголовокПодсказкиУсовершенствования(Форма, ТипПодписи)
	
	Элементы = Форма.Элементы;
	
	Если ЗначениеЗаполнено(ТипПодписи) Тогда
		
		Элементы.ГруппаУсовершенствоватьПодписи.Доступность = 
			ТипПодписи <> ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.ОбычнаяCMS")
			И ТипПодписи <> ПредопределенноеЗначение("Перечисление.ТипыПодписиКриптографии.БазоваяCAdESBES");
		
		Если Элементы.ГруппаУсовершенствоватьПодписи.Доступность Тогда
			
			Элементы.ДекорацияУсовершенствованиеРасширеннаяПодсказка.Заголовок = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Подписи, добавленные ранее и полученные извне, будут усовершенствованы для длительного хранения до выбранного типа: %1.'"),
				ТипПодписи);
			
		Иначе
			Элементы.ДекорацияУсовершенствованиеРасширеннаяПодсказка.Заголовок = 
				НСтр("ru = 'Подписи, добавленные ранее и полученные извне, будут усовершенствованы для длительного хранения до выбранного типа.'");
		КонецЕсли;
		
	Иначе
		Элементы.ДекорацияУсовершенствованиеРасширеннаяПодсказка.Заголовок = 
			НСтр("ru = 'Не выбран тип подписи для документов.'");
		Элементы.ГруппаУсовершенствоватьПодписи.Доступность = Ложь;
	КонецЕсли;

КонецПроцедуры

// Для процедуры НастроитьФормуОбщихНастроек.
Процедура УстановитьЗаголовокЭлектроннаяПодписьНаСервере(Форма)
	
	Если ОбщегоНазначения.РазделениеВключено() Тогда
		Возврат;
	КонецЕсли;
	
	ИнформационнаяБазаФайловая = ОбщегоНазначения.ИнформационнаяБазаФайловая();
	
	НаборКонстант = Форма.НаборКонстант;
	Элементы = Форма.Элементы;
	
	Если НаборКонстант.ИспользоватьЭлектронныеПодписи Тогда
		ЗаголовокФлажка = НСтр("ru = 'Проверять подписи и сертификаты на сервере'");
		ПодсказкаФлажка =
			НСтр("ru = 'Позволяет не устанавливать программу электронной подписи на компьютер пользователя для проверки электронных подписей и сертификатов.'");
	Иначе
		ЗаголовокФлажка = НСтр("ru = 'Проверять сертификаты на сервере'");
		ПодсказкаФлажка =
			НСтр("ru = 'Позволяет не устанавливать программу электронной подписи на компьютер пользователя для проверки сертификатов.'");
	КонецЕсли;
	
	Элементы.ПроверятьЭлектронныеПодписиНаСервере.Заголовок = ЗаголовокФлажка;
	
	Если ИнформационнаяБазаФайловая Тогда
		ПодсказкаНаСервере = НСтр("ru = 'Важно: на компьютер, где работает веб-сервер, подключенный к файловой информационной базе, должна быть установлена хотя бы одна <a href=%1>программа электронной подписи</a> из списка.'");
	Иначе
		ПодсказкаНаСервере = НСтр("ru = 'Важно: на каждый компьютер, где работает сервер 1С:Предприятия, должна быть установлена хотя бы одна <a href=%1>программа электронной подписи</a> из списка.'");
	КонецЕсли;
	
	ПодсказкаФлажка = ПодсказкаФлажка + Символы.ПС + Символы.ПС + ПодсказкаНаСервере;
	
	Элементы.ПроверятьЭлектронныеПодписиНаСервереРасширеннаяПодсказка.Заголовок = 
		СтроковыеФункции.ФорматированнаяСтрока(ПодсказкаФлажка, "Программа");
	
	Если Не НаборКонстант.ИспользоватьЭлектронныеПодписи Тогда
		ЗаголовокФлажка = НСтр("ru = 'Шифровать и расшифровывать на сервере'");
		ПодсказкаФлажка =
			НСтр("ru = 'Позволяет не устанавливать программу электронной подписи и сертификат на компьютер пользователя для шифрования и расшифровки.'");
		
	ИначеЕсли Не НаборКонстант.ИспользоватьШифрование Тогда
		ЗаголовокФлажка = НСтр("ru = 'Подписывать на сервере'");
		ПодсказкаФлажка =
		НСтр("ru = 'Позволяет не устанавливать программу электронной подписи и сертификат на компьютер пользователя для подписания.'");
	Иначе
		ЗаголовокФлажка = НСтр("ru = 'Подписывать и шифровать на сервере'");
		ПодсказкаФлажка =
			НСтр("ru = 'Позволяет не устанавливать программу электронной подписи и сертификат на компьютер пользователя для подписания, шифрования и расшифровки.'");
	КонецЕсли;
		
	Элементы.СоздаватьЭлектронныеПодписиНаСервере.Заголовок = ЗаголовокФлажка;
	
	Если ИнформационнаяБазаФайловая Тогда
		ПодсказкаНаСервере = НСтр("ru = 'Важно: на компьютер, где работает веб-сервер, подключенный к файловой информационной базе, должна быть установлена <a href=%1>программа электронной подписи</a> и <a href=%2>сертификат</a> с закрытым ключом.'");
	Иначе
		ПодсказкаНаСервере = НСтр("ru = 'Важно: на каждый компьютер, где работает сервер 1С:Предприятия, должна быть установлена <a href=%1>программа электронной подписи</a> и <a href=%2>сертификат</a> с закрытым ключом.'"); 
	КонецЕсли;
	
	ПодсказкаФлажка = ПодсказкаФлажка + Символы.ПС + Символы.ПС + ПодсказкаНаСервере;
	
	Элементы.СоздаватьЭлектронныеПодписиНаСервереРасширеннаяПодсказка.Заголовок = 
		СтроковыеФункции.ФорматированнаяСтрока(ПодсказкаФлажка, "Программы", "Сертификаты");
		
КонецПроцедуры

#Область СвойстваКонвертаXML

Функция ОбработатьУзелSignedInfo(УзелSignedInfo, СвойстваКонвертаXML)
	
	Если Не ПроверитьУникальностьУзла(УзелSignedInfo, СвойстваКонвертаXML) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	МассивУзловReference = Новый Массив;
	
	Для Каждого ДочернийУзел Из УзелSignedInfo.ДочерниеУзлы Цикл
		Если ДочернийУзел.ЛокальноеИмя = "CanonicalizationMethod" Тогда
			Если Не ПолучитьАтрибут(ДочернийУзел, "Algorithm", СвойстваКонвертаXML,
						"АлгоритмКанонизации", СвойстваКонвертаXML.ПроверкаПодписи) Тогда
				Возврат Ложь;
			КонецЕсли;
		ИначеЕсли ДочернийУзел.ЛокальноеИмя = "SignatureMethod" Тогда
			Если Не ПолучитьАтрибут(ДочернийУзел, "Algorithm", СвойстваКонвертаXML,
						"АлгоритмПодписи", СвойстваКонвертаXML.ПроверкаПодписи) Тогда
				Возврат Ложь;
			КонецЕсли;
		ИначеЕсли ДочернийУзел.ЛокальноеИмя = "Reference" Тогда
			МассивУзловReference.Добавить(ДочернийУзел);
		КонецЕсли;
	КонецЦикла;
	
	Возврат ОбработатьУзлыReference(МассивУзловReference, СвойстваКонвертаXML);
		
КонецФункции

Функция ОбработатьУзлыReference(МассивУзловReference, СвойстваКонвертаXML)
	
	Для Каждого УзелReference Из МассивУзловReference Цикл
		ХешируемаяОбласть = ОписаниеХешируемойОбласти();
		
		ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(Истина, ХешируемаяОбласть, Истина);
		Если Не ПолучитьАтрибут(УзелReference, "URI", СвойстваКонвертаXML,
					"ИдентификаторУзла", Ложь, ДополнительныеПараметры) Тогда
			Возврат Ложь;
		КонецЕсли;
		
		Для Каждого ДочернийУзел Из УзелReference.ДочерниеУзлы Цикл
			Если ДочернийУзел.ЛокальноеИмя = "Transforms" Тогда
				Если Не ОбработатьУзелTransforms(ДочернийУзел, СвойстваКонвертаXML, ХешируемаяОбласть) Тогда
					Возврат Ложь;
				КонецЕсли;
			ИначеЕсли ДочернийУзел.ЛокальноеИмя = "DigestMethod" Тогда
				ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(Истина, ХешируемаяОбласть);
				Если Не ПолучитьАтрибут(ДочернийУзел, "Algorithm", СвойстваКонвертаXML, "АлгоритмХеширования",
							СвойстваКонвертаXML.ПроверкаПодписи, ДополнительныеПараметры) Тогда
					Возврат Ложь;
				КонецЕсли;
			ИначеЕсли ДочернийУзел.ЛокальноеИмя = "DigestValue" Тогда
				ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(Ложь, ХешируемаяОбласть);
				Если Не ПолучитьЗначение(ДочернийУзел, СвойстваКонвертаXML,
						"ЗначениеХеша", ХешируемаяОбласть, Истина) Тогда
					Возврат Ложь;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		СвойстваКонвертаXML.ХешируемыеОбласти.Добавить(ХешируемаяОбласть);
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

Функция ОбработатьУзелTransforms(УзелTransforms, СвойстваКонвертаXML, ХешируемаяОбласть)
	
	ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(Истина);
	Если Не ПроверитьУникальностьУзла(УзелTransforms, СвойстваКонвертаXML, ДополнительныеПараметры) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Для Каждого ДочернийУзел Из УзелTransforms.ДочерниеУзлы Цикл
		Если ДочернийУзел.ЛокальноеИмя = "Transform" Тогда
			ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(Истина, ХешируемаяОбласть);
			Если Не ПолучитьАтрибут(ДочернийУзел, "Algorithm", СвойстваКонвертаXML, "АлгоритмыТрансформации",
						СвойстваКонвертаXML.ПроверкаПодписи, ДополнительныеПараметры) Тогда
				Возврат Ложь;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Истина;

КонецФункции

Функция ОбработатьУзелKeyInfo(УзелKeyInfo, СвойстваКонвертаXML)
	
	Если Не ПроверитьУникальностьУзла(УзелKeyInfo, СвойстваКонвертаXML) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Для Каждого ДочернийУзел Из УзелKeyInfo.ДочерниеУзлы Цикл
		Если ДочернийУзел.ЛокальноеИмя = "X509Data" Тогда
			Если Не ОбработатьУзелX509Data(ДочернийУзел, СвойстваКонвертаXML) Тогда
				Прервать;
			КонецЕсли;
		ИначеЕсли ДочернийУзел.ЛокальноеИмя = "KeyInfoReference"
		      Или ДочернийУзел.ЛокальноеИмя = "SecurityTokenReference" Тогда
			Если Не ОбработатьУзелСоСсылкойНаСертификат(ДочернийУзел, СвойстваКонвертаXML) Тогда
				Прервать;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

Функция ОбработатьУзелX509Data(УзелX509Data, СвойстваКонвертаXML)
	
	Если Не ПроверитьУникальностьУзла(УзелX509Data, СвойстваКонвертаXML) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Для Каждого ДочернийУзел Из УзелX509Data.ДочерниеУзлы Цикл
		Если ДочернийУзел.ЛокальноеИмя <> "X509Certificate" Тогда
			Продолжить;
		КонецЕсли;
		Если Не ПолучитьЗначение(ДочернийУзел, СвойстваКонвертаXML,
					"ЗначениеСертификата", СвойстваКонвертаXML.Сертификат) Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

Функция ОбработатьУзелСоСсылкойНаСертификат(УзелСоСсылкойНаСертификат, СвойстваКонвертаXML)
	
	Если Не ПроверитьУникальностьУзла(УзелСоСсылкойНаСертификат, СвойстваКонвертаXML) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(Ложь);
	
	Для Каждого ДочернийУзел Из УзелСоСсылкойНаСертификат.ДочерниеУзлы Цикл
		Если ДочернийУзел.ЛокальноеИмя <> "Reference" Тогда
			Продолжить;
		КонецЕсли;
		ДополнительныеПараметры.Свойства = СвойстваКонвертаXML.Сертификат;
		Если Не ПолучитьАтрибут(ДочернийУзел, "URI", СвойстваКонвертаXML,
				"ИдентификаторУзла", Ложь, ДополнительныеПараметры) Тогда
			Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

// Параметры:
//  ДокументDOM      - ДокументDOM
//  ЛокальноеИмя     - Строка
//  ПространствоИмен - Строка
//  ТекстОшибки      - Строка
//  ИсключаемыеУзлы  - Неопределено
//                   - Массив из ЭлементDOM
//  ОшибкаЕслиНайден - Булево
//
// Возвращаемое значение:
//  ЭлементDOM
//
Функция НайтиУзелПоИмени(ДокументDOM, ЛокальноеИмя, ПространствоИмен,
			ТекстОшибки, ИсключаемыеУзлы = Неопределено,
			ПространстваИменДоУзлаВключительно = Неопределено, ОшибкаЕслиНайден = Ложь)
	
	УзелНайден = Ложь;
	ПространстваИменДоУзла =
		?(ПространстваИменДоУзлаВключительно <> Неопределено, Новый Массив, Неопределено);
	
	Для Каждого Узел Из ДокументDOM.ДочерниеУзлы Цикл
		Если ИсключаемыеУзлы <> Неопределено
		   И ИсключаемыеУзлы.Найти(Узел) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Если Узел.ЛокальноеИмя = ЛокальноеИмя
		   И Узел.URIПространстваИмен = ПространствоИмен Тогда
			Результат = Узел;
			УзелНайден = Истина;
			Прервать;
		КонецЕсли;
		ПространстваИменВложенныхУзлов =
			?(ПространстваИменДоУзла <> Неопределено, Новый Массив, Неопределено);
		Результат = НайтиУзелПоИмени(Узел, ЛокальноеИмя, ПространствоИмен,
			Null, ИсключаемыеУзлы, ПространстваИменВложенныхУзлов);
		Если Результат <> Неопределено Тогда
			УзелНайден = Истина;
			ДобавитьПространстваИмен(ПространстваИменДоУзла,
				Узел, ПространстваИменВложенныхУзлов);
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если Не УзелНайден Тогда
		Результат = Неопределено;
	КонецЕсли;
	
	Если ТекстОшибки = Null Тогда
		ПространстваИменДоУзлаВключительно = ПространстваИменДоУзла;
		Возврат Результат;
	КонецЕсли;
	
	Если УзелНайден И ОшибкаЕслиНайден Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В документе XML найдено более одного узла ""%1"" с пространством имен ""%2"".'"),
			ЛокальноеИмя,
			ПространствоИмен);
	ИначеЕсли Не УзелНайден И Не ОшибкаЕслиНайден Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В документе XML не найден узел ""%1"" с пространством имен ""%2"".'"),
			ЛокальноеИмя,
			ПространствоИмен);
	КонецЕсли;
	
	Если Результат <> Неопределено
	   И ПространстваИменДоУзлаВключительно <> Неопределено Тогда
		
		ДобавитьПространстваИмен(ПространстваИменДоУзлаВключительно,
			Результат, ПространстваИменДоУзла);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  ДокументDOM       - ДокументDOM
//  ИдентификаторУзла - Строка
//  ТекстОшибки       - Строка
//  ИсключаемыеУзлы   - Массив из ЭлементDOM
//  ПространстваИменДоУзла - Неопределено
//                         - Массив из Строка
//  ОшибкаЕслиНайден - Булево
//
// Возвращаемое значение:
//  ЭлементDOM
//
Функция НайтиУзелПоИдентификатору(ДокументDOM, ИдентификаторУзла, ТекстОшибки,
			ИсключаемыеУзлы = Неопределено, ПространстваИменДоУзла = Неопределено, ОшибкаЕслиНайден = Ложь)
	
	УзелНайден = Ложь;
	ИмяАтрибутаИдентификатора = "Id";
	
	Для Каждого Узел Из ДокументDOM.ДочерниеУзлы Цикл
		Если Узел.Атрибуты = Неопределено
		 Или ИсключаемыеУзлы <> Неопределено
		   И ИсключаемыеУзлы.Найти(Узел) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Для Каждого Атрибут Из Узел.Атрибуты Цикл
			Если ВРег(Атрибут.ЛокальноеИмя) = ВРег(ИмяАтрибутаИдентификатора)
			   И Атрибут.ЗначениеУзла = ИдентификаторУзла Тогда
				Результат = Узел;
				УзелНайден = Истина;
				Прервать;
			КонецЕсли;
		КонецЦикла;
		Если УзелНайден Тогда
			Прервать;
		КонецЕсли;
		ПространстваИменВложенныхУзлов =
			?(ПространстваИменДоУзла <> Неопределено, Новый Массив, Неопределено);
		Результат = НайтиУзелПоИдентификатору(Узел,
			ИдентификаторУзла, Null, ИсключаемыеУзлы, ПространстваИменВложенныхУзлов);
		Если Результат <> Неопределено Тогда
			УзелНайден = Истина;
			ДобавитьПространстваИмен(ПространстваИменДоУзла,
				Узел, ПространстваИменВложенныхУзлов);
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Если Не УзелНайден Тогда
		Результат = Неопределено;
	КонецЕсли;
	
	Если ТекстОшибки = Null Тогда
		Возврат Результат;
	КонецЕсли;
	
	Если УзелНайден И ОшибкаЕслиНайден Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В документе XML найдено более одного узла с атрибутом ""%1"" и значением ""%2"".'"),
			ИмяАтрибутаИдентификатора,
			ИдентификаторУзла);
	ИначеЕсли Не УзелНайден И Не ОшибкаЕслиНайден Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В документе XML не найден узел с атрибутом ""%1"" и значением ""%2"".'"),
			ИмяАтрибутаИдентификатора,
			ИдентификаторУзла);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Процедура ДобавитьПространстваИмен(ПространстваИмен, Узел, ПространстваИменВложенныхУзлов)
	
	Если ПространстваИмен <> Неопределено Тогда
		Для Каждого Атрибут Из Узел.Атрибуты Цикл
			Если Атрибут.Префикс <> "xmlns" Тогда
				Продолжить;
			КонецЕсли;
			ПространствоИмен = Атрибут.ИмяУзла + "=""" + Атрибут.ЗначениеУзла + """";
			Если ПространстваИмен.Найти(ПространствоИмен) = Неопределено Тогда
				ПространстваИмен.Добавить(ПространствоИмен);
			КонецЕсли;
		КонецЦикла;
		Для Каждого ПространствоИмен Из ПространстваИменВложенныхУзлов Цикл
			Если ПространстваИмен.Найти(ПространствоИмен) = Неопределено Тогда
				ПространстваИмен.Добавить(ПространствоИмен);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

Функция ПолучитьЗначение(ЭлементDOM, СвойстваКонвертаXML, ИмяСвойства, Свойства = Неопределено, МножественноеПодписание = Ложь)
	
	Значение = ЭлементDOM.ТекстовоеСодержимое;
	
	ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(МножественноеПодписание, Свойства);
	
	Результат = ПроверитьУстановитьЗначение(Значение,
		ЭлементDOM, "", СвойстваКонвертаXML, ИмяСвойства, ДополнительныеПараметры);
	
	Возврат Результат;
	
КонецФункции

Функция ДополнительныеПараметрыАтрибута(МножественноеПодписание, Свойства = Неопределено, ИмяСРодителем = Ложь)
	
	Структура = Новый Структура;
	Структура.Вставить("МножественноеПодписание", МножественноеПодписание);
	Структура.Вставить("Свойства", Свойства);
	Структура.Вставить("ИмяСРодителем", ИмяСРодителем);
	
	Возврат Структура;
	
КонецФункции

Функция ПолучитьАтрибут(ЭлементDOM, ИмяАтрибута, СвойстваКонвертаXML, ИмяСвойства,
			ЗначениеВНижнийРегистр = Ложь, ДополнительныеПараметры = Неопределено)
	
	Если ДополнительныеПараметры = Неопределено Тогда
		ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(Ложь);
	КонецЕсли;
	
	Атрибут = ЭлементDOM.Атрибуты.ПолучитьИменованныйЭлемент(ИмяАтрибута);
	Если Атрибут = Неопределено Тогда
		СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'В документе XML для узла ""%1"" не найден атрибут ""%2"".'"),
			ЭлементDOM.ЛокальноеИмя, ИмяАтрибута);
		Возврат Ложь;
	КонецЕсли;
	Значение = Атрибут.ЗначениеУзла;
	
	Если ЗначениеВНижнийРегистр Тогда
		Значение = НРег(Значение);
	КонецЕсли;
	
	Результат = ПроверитьУстановитьЗначение(Значение,
		ЭлементDOM, ИмяАтрибута, СвойстваКонвертаXML, ИмяСвойства,
		ДополнительныеПараметры);
	
	Возврат Результат;
	
КонецФункции

Функция ПроверитьУстановитьЗначение(Значение, ЭлементDOM, ИмяАтрибута, СвойстваКонвертаXML, ИмяСвойства, ДополнительныеПараметры)
	
	Если Не ПроверитьУникальностьУзла(ЭлементDOM, СвойстваКонвертаXML, ДополнительныеПараметры) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если СвойстваКонвертаXML.ДоступныеСвойства.Свойство(ИмяСвойства) Тогда
		ДоступныеЗначения = СвойстваКонвертаXML.ДоступныеСвойства[ИмяСвойства];
		Если ДоступныеЗначения.ЭтоСтрокаBase64 Или ДоступныеЗначения.ЭтоURI Тогда
			Значение = СокрЛП(Значение);
		КонецЕсли;
		
		Если Не СвойстваКонвертаXML.ПроверкаПодписи
		   И ЗначениеЗаполнено(ДоступныеЗначения.ИмяПараметра) Тогда
		   
			Если Значение <> ДоступныеЗначения.ИмяПараметра И Не ДополнительныеПараметры.МножественноеПодписание Тогда
				Если ЗначениеЗаполнено(ИмяАтрибута) Тогда
					СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'В документе XML для узла ""%1"" в атрибуте ""%2"" должно быть указано значение ""%3"".'"),
						ЭлементDOM.ЛокальноеИмя, ИмяАтрибута, ДоступныеЗначения.ИмяПараметра);
				Иначе
					СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'В документе XML для узла ""%1"" должно быть указано значение ""%2"".'"),
						ЭлементDOM.ЛокальноеИмя, ДоступныеЗначения.ИмяПараметра);
				КонецЕсли;
				Возврат Ложь;
			КонецЕсли;
		
		ИначеЕсли ДоступныеЗначения.ЭтоСтрокаBase64 Тогда
			Попытка
				ЗначениеBase64 = Base64Значение(Значение);
			Исключение
				ЗначениеBase64 = "";
			КонецПопытки;
			Если Не ЗначениеЗаполнено(ЗначениеBase64) Тогда
				Если ЗначениеЗаполнено(ИмяАтрибута) Тогда
					СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'В документе XML для узла ""%1"" в атрибуте ""%2"" указано не Base64 значение ""%3"".'"),
						ЭлементDOM.ЛокальноеИмя, ИмяАтрибута, Значение);
				Иначе
					СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'В документе XML для узла ""%1"" указано не Base64 значение ""%2"".'"),
						ЭлементDOM.ЛокальноеИмя, ИмяАтрибута, Значение);
				КонецЕсли;
				Возврат Ложь;
			КонецЕсли;
			
		ИначеЕсли ДоступныеЗначения.ЭтоURI Тогда
			Если Не СтрНачинаетсяС(Значение, "#")
			 Или СтрДлина(Значение) < 2 Тогда
				Если ЗначениеЗаполнено(ИмяАтрибута) Тогда
					СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'В документе XML для узла ""%1"" в атрибуте ""%2"" указан некорректный URI ""%3"".'"),
						ЭлементDOM.ЛокальноеИмя, ИмяАтрибута, Значение);
				Иначе
					СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'В документе XML для узла ""%1"" указан некорректный URI ""%2"".'"),
						ЭлементDOM.ЛокальноеИмя, ИмяАтрибута, Значение);
				КонецЕсли;
				Возврат Ложь;
			КонецЕсли;
			Значение = Сред(Значение, 2);
			
		ИначеЕсли ЗначениеЗаполнено(ДоступныеЗначения.Значения) Тогда
			Описание = ДоступныеЗначения.Значения.Получить(Значение);
			Если Описание = Неопределено Тогда
				Если ЗначениеЗаполнено(ИмяАтрибута) Тогда
					СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'В документе XML для узла ""%1"" в атрибуте ""%2"" указано недопустимое значение ""%3"".'"),
						ЭлементDOM.ЛокальноеИмя, ИмяАтрибута, Значение);
				Иначе
					СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'В документе XML для узла ""%1"" указано недопустимое значение ""%2"".'"),
						ЭлементDOM.ЛокальноеИмя, ИмяАтрибута, Значение);
				КонецЕсли;
				Возврат Ложь;
			Иначе
				Значение = Описание;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Если ДополнительныеПараметры.Свойства = Неопределено Тогда
		НаборСвойств = СвойстваКонвертаXML;
	Иначе
		НаборСвойств = ДополнительныеПараметры.Свойства;
	КонецЕсли;
	
	Если ТипЗнч(НаборСвойств[ИмяСвойства]) = Тип("Массив") Тогда
		Если НаборСвойств[ИмяСвойства].Найти(Значение) = Неопределено Тогда
			НаборСвойств[ИмяСвойства].Добавить(Значение);
		КонецЕсли;
	Иначе
		НаборСвойств[ИмяСвойства] = Значение;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

Функция ПроверитьУникальностьУзла(ЭлементDOM, СвойстваКонвертаXML, ДополнительныеПараметры = Неопределено)
	
	Если ДополнительныеПараметры = Неопределено Тогда
		ДополнительныеПараметры = ДополнительныеПараметрыАтрибута(Ложь);
	КонецЕсли;
	
	ИмяСвойства = ЭлементDOM.ЛокальноеИмя;
	Если ДополнительныеПараметры.ИмяСРодителем Тогда
		ИмяСвойства = ЭлементDOM.РодительскийУзел.ЛокальноеИмя + "_" + ИмяСвойства;
	КонецЕсли;
	
	Если СвойстваКонвертаXML.ОбязательныеУзлы.Свойство(ИмяСвойства) Тогда
		СвойстваКонвертаXML.ОбязательныеУзлы[ИмяСвойства] = ЭлементDOM;
	КонецЕсли;
	
	Если Не СвойстваКонвертаXML.УникальныеУзлы.Свойство(ИмяСвойства) Тогда
		Возврат Истина;
	КонецЕсли;
	
	Если ДополнительныеПараметры.МножественноеПодписание Тогда
		Если ИмяСвойства = "SignedInfo_Reference" Тогда
			Если СвойстваКонвертаXML.УникальныеУзлы[ИмяСвойства] = Неопределено Тогда
				СвойстваКонвертаXML.УникальныеУзлы[ИмяСвойства] = Новый Массив;
			КонецЕсли;
			СвойстваКонвертаXML.УникальныеУзлы[ИмяСвойства].Добавить(ЭлементDOM);
		Иначе
			СвойстваКонвертаXML.УникальныеУзлы[ИмяСвойства] = ЭлементDOM;
		КонецЕсли;
	Иначе
		
		Если СвойстваКонвертаXML.УникальныеУзлы[ИмяСвойства] <> Неопределено Тогда
			Если ДополнительныеПараметры.ИмяСРодителем Тогда
				СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'В документе XML узел ""%1"" встречается более одного раза в узле ""%2"".'"),
					ЭлементDOM.ЛокальноеИмя,
					ЭлементDOM.РодительскийУзел.ЛокальноеИмя);
			Иначе
				СвойстваКонвертаXML.ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'В документе XML узел ""%1"" встречается более одного раза.'"),
					ИмяСвойства);
			КонецЕсли;
			Возврат Ложь;
		КонецЕсли;
		СвойстваКонвертаXML.УникальныеУзлы[ИмяСвойства] = ЭлементDOM;
	КонецЕсли;
	
	Возврат Истина;
	
КонецФункции

// Параметры:
//  СлужебныеСвойстваКонвертаXML - см. СлужебныеСвойстваКонвертаXML
//
// Возвращаемое значение:
//  Структура:
//   * ТекстОшибки         - Строка
//   * ОбластьSignedInfo   - см. ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбластьXML
//   * ОбластиBody         - Массив из см. ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбластьXML
//   * АлгоритмКанонизации - см. АлгоритмКанонизации
//   * АлгоритмПодписи     - см. АлгоритмПодписиИХеширования
//   * ХешируемыеОбласти   - Массив из см. ОписаниеХешируемойОбласти
//   * ЗначениеПодписи     - Строка - Base64 строка.
//   * Сертификат          - см. ОписаниеСертификата
//   * ПроверкаПодписи     - Булево - когда Ложь, подписание.
//
Функция ВозвращаемыеСвойстваКонвертаXML(СлужебныеСвойстваКонвертаXML = Неопределено)
	
	Результат = Новый Структура;
	Результат.Вставить("ТекстОшибки", "");
	Результат.Вставить("ОбластьSignedInfo");
	Результат.Вставить("ОбластиBody", Новый Массив);
	Результат.Вставить("АлгоритмКанонизации");
	Результат.Вставить("АлгоритмПодписи");
	Результат.Вставить("ХешируемыеОбласти", Новый Массив);
	Результат.Вставить("ЗначениеПодписи", "");
	Результат.Вставить("Сертификат", ОписаниеСертификата());
	Результат.Вставить("ПроверкаПодписи", Ложь);
	
	Если ТипЗнч(СлужебныеСвойстваКонвертаXML) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Результат, СлужебныеСвойстваКонвертаXML);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  ПроверкаПодписи - Булево
//
// Возвращаемое значение:
//  Структура:
//   * ТекстОшибки         - Строка
//   * ОбластьSignedInfo   - см. ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбластьXML
//   * ОбластиBody         - Массив из см. ЭлектроннаяПодписьСлужебныйКлиентСервер.ОбластьXML
//   * АлгоритмКанонизации - см. АлгоритмКанонизации
//   * АлгоритмПодписи     - см. АлгоритмПодписиИХеширования
//   * ХешируемыеОбласти   - Массив из см. ОписаниеХешируемойОбласти
//   * ЗначениеПодписи     - Строка - Base64 строка.
//   * Сертификат          - см. ОписаниеСертификата
//   * ПроверкаПодписи     - Булево - когда Ложь, подписание.
//   * ДоступныеСвойства   - см. ДоступныеСвойстваКонвертаXML
//   * ОбязательныеУзлы    - Структура из КлючИЗначение:
//       * Ключ     - Строка - имя узла или имя узла родителя с именем узла.
//       * Значение - ЭлементDOM
//                  - Неопределено
//   * УникальныеУзлы      - Структура из КлючИЗначение:
//       * Ключ     - Строка - имя узла или имя узла родителя с именем узла.
//       * Значение - ЭлементDOM
//                  - Неопределено
//
Функция СлужебныеСвойстваКонвертаXML(ПроверкаПодписи)
	
	Результат = ВозвращаемыеСвойстваКонвертаXML();
	Результат.ПроверкаПодписи = ПроверкаПодписи;
	Результат.Вставить("ДоступныеСвойства", ДоступныеСвойстваКонвертаXML(ПроверкаПодписи));
	Результат.Вставить("ОбязательныеУзлы", Новый Структура(
		"SignedInfo,SignatureValue,KeyInfo,
		|CanonicalizationMethod,SignatureMethod,SignedInfo_Reference,
		|DigestMethod,DigestValue"));
	Результат.Вставить("УникальныеУзлы", Новый Структура(
		"SignedInfo,SignatureValue,KeyInfo,
		|CanonicalizationMethod,SignatureMethod,SignedInfo_Reference,
		|Transforms,DigestMethod,DigestValue,
		|X509Data,X509Certificate,SecurityTokenReference,Reference"));
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * ИдентификаторУзла      - Строка
//   * АлгоритмыТрансформации - Массив из см. АлгоритмКанонизации
//   * АлгоритмХеширования    - см. АлгоритмПодписиИХеширования
//   * ЗначениеХеша           - Строка - Base64 строка.
//
Функция ОписаниеХешируемойОбласти()
	
	Результат = Новый Структура;
	Результат.Вставить("ИдентификаторУзла", "");
	Результат.Вставить("АлгоритмыТрансформации", Новый Массив);
	Результат.Вставить("АлгоритмХеширования", "");
	Результат.Вставить("ЗначениеХеша", "");
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * ИдентификаторУзла   - Строка
//   * ЗначениеСертификата - Строка - Base64 строка.
//
Функция ОписаниеСертификата()
	
	Результат = Новый Структура;
	Результат.Вставить("ИдентификаторУзла",   "");
	Результат.Вставить("ЗначениеСертификата", "");
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  ПроверкаПодписи - Булево
//
// Возвращаемое значение:
//  Структура:
//   * ИдентификаторУзла      - см. ДоступныеЗначения
//   * АлгоритмКанонизации    - см. ДоступныеЗначения
//   * АлгоритмыТрансформации - см. ДоступныеЗначения
//   * ЗначениеХеша           - см. ДоступныеЗначения
//   * ЗначениеПодписи        - см. ДоступныеЗначения
//   * ЗначениеСертификата    - см. ДоступныеЗначения
//   * АлгоритмПодписи        - см. ДоступныеЗначения
//   * АлгоритмХеширования    - см. ДоступныеЗначения
//
Функция ДоступныеСвойстваКонвертаXML(ПроверкаПодписи)
	
	Результат = Новый Структура;
	Результат.Вставить("ИдентификаторУзла", ДоступныеЗначения("", , Истина));
	
	Результат.Вставить("АлгоритмКанонизации", ДоступныеЗначения(""));
	// Canonical XML 1.0.
	Значения = Результат.АлгоритмКанонизации.Значения;
	Значения.Вставить("http://www.w3.org/TR/2001/REC-xml-c14n-20010315", АлгоритмКанонизации("c14n", 0, 0));
	Если ПроверкаПодписи Тогда
		Значения.Вставить("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#", АлгоритмКанонизации("c14n", 0, 0));
	КонецЕсли;
	Значения.Вставить("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments", АлгоритмКанонизации("c14n", 0, 1));
	// Canonical XML 1.1.
	Значения.Вставить("http://www.w3.org/2006/12/xml-c14n11", АлгоритмКанонизации("c14n", 2, 0));
	Если ПроверкаПодписи Тогда
		Значения.Вставить("http://www.w3.org/2006/12/xml-c14n11#", АлгоритмКанонизации("c14n", 2, 0));
	КонецЕсли;
	Значения.Вставить("http://www.w3.org/2006/12/xml-c14n11#WithComments", АлгоритмКанонизации("c14n", 2, 1));
	// Exclusive XML Canonicalization 1.0.
	Значения.Вставить("http://www.w3.org/2001/10/xml-exc-c14n#", АлгоритмКанонизации("c14n", 1, 0));
	Если ПроверкаПодписи Тогда
		Значения.Вставить("http://www.w3.org/2001/10/xml-exc-c14n", АлгоритмКанонизации("c14n", 1, 0));
	КонецЕсли;
	Значения.Вставить("http://www.w3.org/2001/10/xml-exc-c14n#WithComments", АлгоритмКанонизации("c14n", 1, 1));
	Если ПроверкаПодписи Тогда
		ПривестиКлючиКНижнемуРегистру(Результат.АлгоритмКанонизации.Значения);
	КонецЕсли;
	
	Результат.Вставить("АлгоритмыТрансформации", ДоступныеЗначения(""));
	Значения = Новый Соответствие(Новый ФиксированноеСоответствие(Значения));
	Результат.АлгоритмыТрансформации.Значения = Значения;
	Значения.Вставить("urn://smev-gov-ru/xmldsig/transform", АлгоритмКанонизации("smev", 0, 0));
	Значения.Вставить("http://www.w3.org/2000/09/xmldsig#enveloped-signature", АлгоритмКанонизации("envsig", 0, 0));
	Если ПроверкаПодписи Тогда
		ПривестиКлючиКНижнемуРегистру(Результат.АлгоритмыТрансформации.Значения);
	КонецЕсли;
	
	Результат.Вставить("ЗначениеХеша",        ДоступныеЗначения("%DigestValue%", Истина));
	Результат.Вставить("ЗначениеПодписи",     ДоступныеЗначения("%SignatureValue%", Истина));
	Результат.Вставить("ЗначениеСертификата", ДоступныеЗначения("%BinarySecurityToken%", Истина));
	
	Результат.Вставить("АлгоритмПодписи",     ДоступныеЗначения("%SignatureMethod%"));
	Результат.Вставить("АлгоритмХеширования", ДоступныеЗначения("%DigestMethod%"));
	
	Наборы = ЭлектроннаяПодписьСлужебныйКлиентСервер.НаборыАлгоритмовДляСозданияПодписи();
	Для Каждого Набор Из Наборы Цикл
		Результат.АлгоритмПодписи.Значения.Вставить(Набор.ИмяАлгоритмаПодписиXML,
			АлгоритмПодписиИХеширования(Набор.ИмяАлгоритмаПодписиXML, Набор.ИдентификаторАлгоритмаПодписи));
		Результат.АлгоритмХеширования.Значения.Вставить(Набор.ИмяАлгоритмаХешированияXML,
			АлгоритмПодписиИХеширования(Набор.ИмяАлгоритмаХешированияXML, Набор.ИдентификаторАлгоритмаХеширования));
	КонецЦикла;
	Если ПроверкаПодписи Тогда
		ПривестиКлючиКНижнемуРегистру(Результат.АлгоритмПодписи.Значения);
		ПривестиКлючиКНижнемуРегистру(Результат.АлгоритмХеширования.Значения);
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  Имя           - Строка
//  Идентификатор - Строка
//
// Возвращаемое значение:
//  Структура:
//   * Имя           - Строка
//   * Идентификатор - Строка
//
Функция АлгоритмПодписиИХеширования(Имя, Идентификатор)
	
	Результат = Новый Структура;
	Результат.Вставить("Имя", Имя);
	Результат.Вставить("Идентификатор", Идентификатор);
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  Вид            - Строка
//  Версия         - Число
//  СКомментариями - Число
//
// Возвращаемое значение:
//  Структура:
//   * Вид            - Строка
//   * Версия         - Число
//   * СКомментариями - Число
//
Функция АлгоритмКанонизации(Вид, Версия, СКомментариями) Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("Вид", Вид);
	Результат.Вставить("Версия", Версия);
	Результат.Вставить("СКомментариями", СКомментариями);
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//  ИмяПараметра    - Строка
//  ЭтоСтрокаBase64 - Булево
//  ЭтоURI          - Булево
//
// Возвращаемое значение:
//  Структура:
//   * ИмяПараметра    - Строка
//   * ЭтоСтрокаBase64 - Булево
//   * ЭтоURI          - Булево
//   * Значения - Соответствие из КлючИЗначение:
//       ** Ключ     - Строка
//       ** Значение - Структура
//
Функция ДоступныеЗначения(ИмяПараметра, ЭтоСтрокаBase64 = Ложь, ЭтоURI = Ложь)
	
	Результат = Новый Структура;
	Результат.Вставить("ИмяПараметра", ИмяПараметра);
	Результат.Вставить("Значения", Новый Соответствие);
	Результат.Вставить("ЭтоСтрокаBase64", ЭтоСтрокаBase64);
	Результат.Вставить("ЭтоURI", ЭтоURI);
	
	Возврат Результат;
	
КонецФункции

Процедура ПривестиКлючиКНижнемуРегистру(Значения)
	
	НовыеЗначения = Новый Соответствие;
	
	Для Каждого КлючИЗначение Из Значения Цикл
		НовыеЗначения.Вставить(НРег(КлючИЗначение.Ключ), КлючИЗначение.Значение);
	КонецЦикла;
	
	Значения = НовыеЗначения;
	
КонецПроцедуры

#КонецОбласти

#Область КлассификаторОшибокКриптографии

Функция ОшибкаПоКлассификатору(ТекстДляПоискаВКлассификаторе, ОшибкаНаСервере = Ложь) Экспорт
	
	ОшибкаПоКлассификатору = ЭлектроннаяПодписьСлужебныйПовтИсп.ОшибкаПоКлассификатору(
		ТекстДляПоискаВКлассификаторе, ОшибкаНаСервере);
		
	Если ОшибкаПоКлассификатору = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ПредставлениеОшибки = ПредставлениеОшибки();
	ЗаполнитьЗначенияСвойств(ПредставлениеОшибки, ОшибкаПоКлассификатору);
	
	Возврат ПредставлениеОшибки;
	
КонецФункции

Функция ПредставлениеОшибки() Экспорт
	
	ПредставлениеОшибки = Новый Структура;
	ПредставлениеОшибки.Вставить("Ссылка", "");
	ПредставлениеОшибки.Вставить("Причина", "");
	ПредставлениеОшибки.Вставить("Решение", "");
	ПредставлениеОшибки.Вставить("СпособУстранения", "");
	ПредставлениеОшибки.Вставить("ДействияДляУстранения");
	ПредставлениеОшибки.Вставить("ТребуетПроверки", Ложь);
	ПредставлениеОшибки.Вставить("СертификатОтозван", Ложь);
	
	Возврат ПредставлениеОшибки;
	
КонецФункции

Функция КлассификаторОшибокКриптографии() Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	Если Не ОбщегоНазначения.РазделениеВключено() 
		И Метаданные.ОбщиеМодули.Найти("ЭлектроннаяПодписьСлужебныйЛокализация") <> Неопределено
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда
			
		МодульЭлектроннаяПодписьСлужебныйЛокализация = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьСлужебныйЛокализация");
		
		Попытка
			ТекстОшибки = МодульЭлектроннаяПодписьСлужебныйЛокализация.ОбновитьКлассификатор();
		Исключение
			ТекстОшибки = ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		КонецПопытки;
		
		Если ЗначениеЗаполнено(ТекстОшибки) Тогда
			Комментарий = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось обновить классификатор ошибок криптографии по причине:
				           |%1'"), ТекстОшибки);
			ЗаписьЖурналаРегистрации(
				НСтр("ru = 'Электронная подпись.Обновление классификатора ошибок'",
				ОбщегоНазначения.КодОсновногоЯзыка()),
				УровеньЖурналаРегистрации.Ошибка,,,
				Комментарий);
		КонецЕсли;
		
	КонецЕсли;
	
	ДанныеКлассификатора = Константы.КлассификаторОшибокКриптографии.Получить().Получить();
	
	Версия = Неопределено;
	
	Если ТипЗнч(ДанныеКлассификатора) = Тип("Структура") Тогда
		Попытка
			Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(ДанныеКлассификатора.Версия, "3.0.1.13") < 0 Тогда
				Версия = Неопределено;
			Иначе
				Версия = ДанныеКлассификатора.Версия;
			КонецЕсли;
		Исключение
			Версия = Неопределено;
		КонецПопытки;
	Иначе
		ДанныеКлассификатора = Неопределено;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(ДанныеКлассификатора)
		Или Версия = Неопределено Тогда
		
		Если Метаданные.ОбщиеМодули.Найти("ЭлектроннаяПодписьСлужебныйЛокализация") = Неопределено Тогда
			Возврат Неопределено;
		КонецЕсли;
		
		МодульЭлектроннаяПодписьСлужебныйЛокализация = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьСлужебныйЛокализация");
		ДанныеКлассификатора = МодульЭлектроннаяПодписьСлужебныйЛокализация.КлассификаторОшибокКриптографии();
		Если Не ЗначениеЗаполнено(ДанныеКлассификатора) Тогда
			Возврат Неопределено;
		КонецЕсли;
	КонецЕсли;
	
	НовыйКлассификаторОшибокКриптографии = НовыйКлассификаторОшибокКриптографии();
	Для Каждого Строка Из ДанныеКлассификатора.Классификатор Цикл
		НоваяСтрока = НовыйКлассификаторОшибокКриптографии.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
		НоваяСтрока.ТекстОшибкиНижнийРегистр = НРег(НоваяСтрока.ТекстОшибки);
	КонецЦикла;
	
	Возврат НовыйКлассификаторОшибокКриптографии;
	
КонецФункции

Функция НовыйКлассификаторОшибокКриптографии()
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("ТекстОшибки",
		Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(500)));
	Результат.Колонки.Добавить("ТекстОшибкиНижнийРегистр",
		Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(500)));
	Результат.Колонки.Добавить("Причина",
		Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(500)));
	Результат.Колонки.Добавить("Решение",
		Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(750)));
	Результат.Колонки.Добавить("СпособУстранения",
		Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(500)));
	Результат.Колонки.Добавить("Ссылка",
		Новый ОписаниеТипов("Строка", Новый КвалификаторыСтроки(500)));
		
	Результат.Колонки.Добавить("ТолькоСервер",    Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ТолькоКлиент",    Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ТребуетПроверки", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("СертификатОтозван", Новый ОписаниеТипов("Булево"));
	
	Возврат Результат;
	
КонецФункции

// Только для внутреннего использования.
Процедура ЗаписатьДанныеКлассификатора(ДанныеКлассификатора, ДатаПоследнегоИзменения = Неопределено) Экспорт
	
	Если ДанныеКлассификатора <> Неопределено Тогда
		
		Константы.КлассификаторОшибокКриптографии.Установить(
			Новый ХранилищеЗначения(ПредставлениеКлассификатораОшибок(ДанныеКлассификатора), Новый СжатиеДанных(9)));
	
	КонецЕсли;
	
	Если ДатаПоследнегоИзменения <> Неопределено Тогда
		Константы.ДатаПоследнегоОбновленияКлассификатораОшибок.Установить(
			ДатаПоследнегоИзменения);
	КонецЕсли;
	
КонецПроцедуры

// Только для внутреннего использования.
Функция ПредставлениеКлассификатораОшибок(ДанныеКлассификатора) Экспорт
	
	ЧтениеJSON = Новый ЧтениеJSON;
	Если ТипЗнч(ДанныеКлассификатора) = Тип("Строка") Тогда
		ЧтениеJSON.УстановитьСтроку(ДанныеКлассификатора);
	Иначе
		ЧтениеJSON.ОткрытьПоток(ДанныеКлассификатора.ОткрытьПотокДляЧтения());
	КонецЕсли;
	
	КлассификаторОшибок = ПрочитатьJSON(ЧтениеJSON,, "LastChangeDate");
	ВерсияКлассификатора = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(
		КлассификаторОшибок, "Version", Неопределено);
	ЧтениеJSON.Закрыть();
	
	Классификатор = НовыйКлассификаторОшибокКриптографии();
	
	Для Каждого ИзвестнаяОшибка Из КлассификаторОшибок.Classifier Цикл
		
		НоваяОшибка = Классификатор.Добавить();
		НоваяОшибка.Ссылка           = ИзвестнаяОшибка.Anchor;
		НоваяОшибка.Причина          = ИзвестнаяОшибка.Reason;
		НоваяОшибка.Решение          = ИзвестнаяОшибка.Solution;
		НоваяОшибка.ТолькоСервер     = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ИзвестнаяОшибка, "Server", Ложь);
		НоваяОшибка.ТолькоКлиент     = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ИзвестнаяОшибка, "Client", Ложь);
		Категория = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(ИзвестнаяОшибка, "Category", Неопределено);
		Если ЗначениеЗаполнено(Категория) Тогда
			НоваяОшибка.ТребуетПроверки   = ОшибкаТребуетПерепроверки(Категория);
			НоваяОшибка.СертификатОтозван = ОшибкаСертификатОтозван(Категория);
		КонецЕсли;
		НоваяОшибка.ТекстОшибки      = ИзвестнаяОшибка.ErrorText;
		НоваяОшибка.СпособУстранения = ИзвестнаяОшибка.RepairMethods;
		
	КонецЦикла;
	
	Возврат Новый Структура("Классификатор, Версия", Классификатор, ВерсияКлассификатора);
	
КонецФункции

Функция ОшибкаТребуетПерепроверки(Категория)
	
	Если Категория = "untrustedroot" Или Категория = "no_revocation_check" Или Категория = "chaining" Тогда
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Функция ОшибкаСертификатОтозван(Категория)
	
	Если Категория = "cert_revoked" Тогда
		Возврат Истина;
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

#КонецОбласти

#Область ДиагностикаЭлектроннойПодписи

Процедура ДополнитьТехническойИнформациейОСервере(ТехническаяИнформация,
			ПроверенныеПутиКМодулямПрограммНаКлиенте) Экспорт
	
	Если Не ЭлектроннаяПодпись.СоздаватьЭлектронныеПодписиНаСервере()
		И Не ЭлектроннаяПодпись.ПроверятьЭлектронныеПодписиНаСервере() Тогда
		
		ТехническаяИнформация = ТехническаяИнформация + Символы.ПС
			+ НСтр("ru = 'Электронная подпись на сервере не используется.'") + Символы.ПС;
	Иначе
		ТехническаяИнформация = ТехническаяИнформация
			+ Символы.ПС + ТехническаяИнформацияОКомпьютере()
			+ Символы.ПС + Символы.ПС + ТехническаяИнформацияОКомпоненте()
			+ Символы.ПС + ТехническаяИнформацияОПрограммах();
	КонецЕсли;
	
	ТехническаяИнформация = ТехническаяИнформация + Символы.ПС
		+ ТехническаяИнформацияОНастройкахПрограммВСправочнике(ПроверенныеПутиКМодулямПрограммНаКлиенте);
	
	Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
		РежимРаботы = ?(ОбщегоНазначения.КлиентПодключенЧерезВебСервер(),
			НСтр("ru = 'Файловый через веб'"), НСтр("ru = 'Файловый'"));
	Иначе
		РежимРаботы = НСтр("ru = 'Клиент-серверный'");
	КонецЕсли;
	
	ТехническаяИнформация = ТехническаяИнформация
		+ Символы.ПС + НСтр("ru = 'Режим работы информационной базы'")+ " - " + РежимРаботы
		+ Символы.ПС + Символы.ПС + СтандартныеПодсистемыСервер.ТехническаяИнформацияОВерсияхПодсистемИРасширениях();
	
КонецПроцедуры

Функция ТехническаяИнформацияОКомпьютере()
	
	ПараметрыЗапуска = ФайловаяСистема.ПараметрыЗапускаПрограммы();
	ПараметрыЗапуска.ДождатьсяЗавершения = Истина;
	ПараметрыЗапуска.ПолучитьПотокВывода = Истина;
	ПараметрыЗапуска.КодировкаПотоков = КодировкаТекста.UTF8;
	
	Если ОбщегоНазначения.ЭтоWindowsСервер() Тогда
		Команда = "echo %username%";
	Иначе
		Команда = "whoami";
	КонецЕсли;
	
	Результат = ФайловаяСистема.ЗапуститьПрограмму(Команда, ПараметрыЗапуска);
	Если Результат.КодВозврата = 0 Тогда
		ИмяПользователяОС = СокрЛП(Результат.ПотокВывода);
	Иначе
		ИмяПользователяОС = "";
	КонецЕсли;
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Сервер (%1):'"), ИмяКомпьютера() + "\" + ИмяПользователяОС) + Символы.ПС
		+ ЭлектроннаяПодписьСлужебныйКлиентСервер.ДиагностическаяИнформацияОКомпьютере();
	
КонецФункции

Функция ТехническаяИнформацияОКомпоненте()
	
	ВерсияКомпоненты = "";
	Попытка 
		ВерсияКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI().ПолучитьВерсию();
	Исключение
		ВерсияКомпоненты = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
	КонецПопытки;
	
	Возврат СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Версия компоненты %1 на сервере - %2'"), "ExtraCryptoAPI", ВерсияКомпоненты); 
	
КонецФункции

Функция ТехническаяИнформацияОПрограммах()
	
	ДиагностическаяИнформация = "";
	
	УстановленныеПрограммыРезультат = УстановленныеКриптопровайдеры();
	
	Если Не УстановленныеПрограммыРезультат.ПроверкаВыполнена Тогда
		ДиагностическаяИнформация = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось автоматически определить программы на ""%1"": %2'"),
			ИмяКомпьютера(), УстановленныеПрограммыРезультат.Ошибка);
	Иначе
		
		Если УстановленныеПрограммыРезультат.Криптопровайдеры.Количество() = 0 Тогда
			ДиагностическаяИнформация = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Нет программ на ""%1"", определенных автоматически'"),
				ИмяКомпьютера());
		Иначе
			ДиагностическаяИнформация = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Автоматически определенные программы на сервере ""%1"":'"), ИмяКомпьютера()) + Символы.ПС;
			
			Для Каждого Программа Из УстановленныеПрограммыРезультат.Криптопровайдеры Цикл
				
				ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
				ПараметрыСоздания.Автоопределение = Ложь;
				ПараметрыСоздания.Программа = Программа;
				ПараметрыСоздания.ПоказатьОшибку = Ложь;
				ПараметрыСоздания.ОписаниеОшибки = Новый Структура;
				
				МенеджерКриптографии = МенеджерКриптографии("", ПараметрыСоздания);
				
				ДиагностическаяИнформация = ДиагностическаяИнформация
					+ ЭлектроннаяПодписьСлужебныйКлиентСервер.ДиагностическаяИнформацияПоПрограмме(Программа,
						МенеджерКриптографии, ПараметрыСоздания.ОписаниеОшибки);
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	ИспользуемыеПрограммы = ЭлектроннаяПодписьСлужебныйВызовСервера.ИспользуемыеПрограммы();
	
	Если ИспользуемыеПрограммы.Количество() = 0 Тогда
		Возврат ДиагностическаяИнформация;
	КонецЕсли;
	
	ДиагностическаяИнформация = ДиагностическаяИнформация + Символы.ПС + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Программы на сервере из справочника ""%1"":'"), ИмяКомпьютера()) + Символы.ПС;
	
	Для Каждого Программа Из ИспользуемыеПрограммы Цикл
		
		ПараметрыСоздания = ПараметрыСозданияМенеджераКриптографии();
		ПараметрыСоздания.Автоопределение = Ложь;
		ПараметрыСоздания.Программа = Программа;
		ПараметрыСоздания.ПоказатьОшибку = Ложь;
		ПараметрыСоздания.ОписаниеОшибки = Новый Структура;
		
		МенеджерКриптографии = МенеджерКриптографии("", ПараметрыСоздания);
		
		ДиагностическаяИнформация = ДиагностическаяИнформация
			+ ЭлектроннаяПодписьСлужебныйКлиентСервер.ДиагностическаяИнформацияПоПрограмме(Программа,
				МенеджерКриптографии, ПараметрыСоздания.ОписаниеОшибки);
	КонецЦикла;
	
	Возврат ДиагностическаяИнформация;
	
КонецФункции

Функция ТехническаяИнформацияОНастройкахПрограммВСправочнике(ПроверенныеПутиКМодулямПрограммНаКлиенте)
	
	ДиагностическаяИнформация = Символы.ПС
		+ НСтр("ru = 'Настройки программ в справочнике:'") + Символы.ПС;
	
	ИспользуемыеПрограммы = ЭлектроннаяПодписьСлужебныйВызовСервера.ИспользуемыеПрограммы();
	Если ИспользуемыеПрограммы.Количество() = 0 Тогда
		ДиагностическаяИнформация = ДиагностическаяИнформация
			+ НСтр("ru = 'В справочник не добавлено ни одной программы.'");
		Возврат ДиагностическаяИнформация;
	КонецЕсли;
	
	Для Каждого Программа Из ИспользуемыеПрограммы Цикл
		ДиагностическаяИнформация = ДиагностическаяИнформация + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = '%1:
			           |	Имя программы: %2
			           |	Тип программы: %3
			           |	Алгоритм подписи: %4
			           |	Алгоритм хеширования: %5
			           |	Алгоритм шифрования: %6
			           |	Режим использования %7'"),
			Программа.Представление,
			Программа.ИмяПрограммы,
			Программа.ТипПрограммы,
			Программа.АлгоритмПодписи,
			Программа.АлгоритмХеширования,
			Программа.АлгоритмШифрования,
			Программа.РежимИспользования) + Символы.ПС;
		
		Если ТребуетсяПутьКПрограмме(Истина) Тогда
			ДобавитьИнформациюОПутиКПрограмме(ДиагностическаяИнформация,
				НСтр("ru = 'Пути к модулям программы на клиенте:'"),
				ПроверенныеПутиКМодулямПрограммНаКлиенте.Получить(Программа.Ссылка).ПутьКПрограмме);
		КонецЕсли;
		Если ТребуетсяПутьКПрограмме() Тогда
			ДобавитьИнформациюОПутиКПрограмме(ДиагностическаяИнформация,
				НСтр("ru = 'Пути к модулям программы на сервере:'"),
				ПутьКПрограмме(Программа.Ссылка).ПутьКПрограмме);
		КонецЕсли;
	КонецЦикла;
	
	Возврат ДиагностическаяИнформация;
	
КонецФункции

Процедура ДобавитьИнформациюОПутиКПрограмме(ДиагностическаяИнформация, Заголовок, ПутьКПрограмме)
	
	ПутиКМодулям = СтрРазделить(ПутьКПрограмме, ":", Ложь);
	
	ДиагностическаяИнформация = ДиагностическаяИнформация
		+ Символы.Таб + Заголовок + Символы.ПС
		+ Символы.Таб + Символы.Таб + """" + СтрСоединить(ПутиКМодулям,
			"""" + Символы.ПС + Символы.Таб + Символы.Таб + """") + """"
		+ Символы.ПС;
	
КонецПроцедуры

// Скачать файл списка отзыва на сервере.
// 
// Параметры:
//  Адреса - Массив из Строка
//  АдресВнутренний - Строка
// 
// Возвращаемое значение:
//  Структура - скачать файл списка отзыва на сервере:
//   * АдресФайла - Строка - адрес, с которого удалось скачать файл 
//   * ИмяФайла - Строка - имя файла 
//   * ДанныеФайла - ДвоичныеДанные
//   * СообщениеОбОшибке - Строка
//
Функция СкачатьФайлСпискаОтзываНаСервере(Знач Адреса, АдресВнутренний = Неопределено) Экспорт
	
	РезультатЗагрузки = Новый Структура;
	РезультатЗагрузки.Вставить("АдресФайла", "");
	РезультатЗагрузки.Вставить("ИмяФайла", "");
	РезультатЗагрузки.Вставить("ДанныеФайла", Неопределено);
	РезультатЗагрузки.Вставить("СообщениеОбОшибке", "");
	
	Если Адреса.Количество() = 0 Тогда
		РезультатЗагрузки.СообщениеОбОшибке = НСтр("ru = 'В сертификате не указаны адреса списков отзыва.'");
		Возврат РезультатЗагрузки;
	КонецЕсли;
	
	ДанныеИзКэша = Неопределено;

	Если ЗначениеЗаполнено(АдресВнутренний) Тогда
		ДанныеИзКэша = ДанныеСпискаОтзываИзБазы(АдресВнутренний);
	
		Если ЗначениеЗаполнено(ДанныеИзКэша.ДатаПроверки) Тогда
			
			ЗаполнитьРезультатЗагрузкиСпискаОтзываИзДанныхКэша(РезультатЗагрузки, ДанныеИзКэша);
			
			ДатаПроверки = ТекущаяУниверсальнаяДата();
			
			Если ЗначениеЗаполнено(РезультатЗагрузки.СообщениеОбОшибке) Тогда
				Если ДанныеИзКэша.ДатаПроверки + 1200 > ДатаПроверки Тогда 
					// Проверка при ошибке не чаще чем раз в 20 минут.
					Возврат РезультатЗагрузки;
				КонецЕсли;
			Иначе
				Если ДанныеИзКэша.ДатаПроверки + 1800 > ДатаПроверки Тогда
					// Если файл был загружен менее 30 минут назад, возвращаем его.
					Возврат РезультатЗагрузки;
				КонецЕсли;
			КонецЕсли;
			
			РезультатЗагрузки.СообщениеОбОшибке = "";
			
		КонецЕсли;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(АдресВнутренний) Тогда
		
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.СпискиОтзываСертификатов");
		ЭлементБлокировки.УстановитьЗначение("АдресВнутренний", АдресВнутренний);
		
		НачатьТранзакцию();
		
		Попытка
			БлокировкаВыполняется = Истина;
 			Блокировка.Заблокировать();
 			БлокировкаВыполняется = Ложь;
			
			НовыеДанныеИзКэша = ДанныеСпискаОтзываИзБазы(АдресВнутренний);
			Если НовыеДанныеИзКэша.ДатаПроверки <> ДанныеИзКэша.ДатаПроверки Тогда
				// Данные в базе изменились до момента установки блокировки.
				ЗаполнитьРезультатЗагрузкиСпискаОтзываИзДанныхКэша(РезультатЗагрузки, НовыеДанныеИзКэша);
				ЗафиксироватьТранзакцию();
				Возврат РезультатЗагрузки; 
			КонецЕсли;
			
			ДатаПоследнегоИзменения = Дата(2021,1,1);
			СкачатьФайлСпискаОтзыва(Адреса, РезультатЗагрузки, ДанныеИзКэша, ДатаПоследнегоИзменения);
			
			УстановитьПривилегированныйРежим(Истина);
			МенеджерЗаписи = РегистрыСведений.СпискиОтзываСертификатов.СоздатьМенеджерЗаписи();
			
			Если ЗначениеЗаполнено(ДанныеИзКэша) И ДанныеИзКэша.ДатаПоследнегоИзменения = ДатаПоследнегоИзменения Тогда
				
				ЗаполнитьЗначенияСвойств(МенеджерЗаписи, ДанныеИзКэша);
				ЗаполнитьРезультатЗагрузкиСпискаОтзываИзДанныхКэша(РезультатЗагрузки, ДанныеИзКэша);
				
			ИначеЕсли РезультатЗагрузки.ДанныеФайла = Неопределено Тогда

				Если ЗначениеЗаполнено(ДанныеИзКэша) Тогда
					// Оставляем данные списка отзыва предыдущие.
					ЗаполнитьЗначенияСвойств(МенеджерЗаписи, ДанныеИзКэша);
					ЗаполнитьРезультатЗагрузкиСпискаОтзываИзДанныхКэша(РезультатЗагрузки, ДанныеИзКэша);
				Иначе
					РезультатЗагрузки.СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Ошибки при попытке загрузить файл(ы):
							 |%1
							 |Подробности см. в Журнале регистрации.'"), СтрСоединить(Адреса, Символы.ПС));
				КонецЕсли;
				
			Иначе
				
				ПериодДействияСпискаОтзыва = ПериодДействияСпискаОтзыва(РезультатЗагрузки.ДанныеФайла);
				
				Если ПериодДействияСпискаОтзыва = Неопределено Тогда
					ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Файл %1 не является списком отзыва.'"), РезультатЗагрузки.АдресФайла);
					ВызватьИсключение ТекстОшибки;
				КонецЕсли;
				
				МенеджерЗаписи.АдресСпискаОтзыва = РезультатЗагрузки.АдресФайла;
				МенеджерЗаписи.СписокОтзыва = Новый ХранилищеЗначения(РезультатЗагрузки.ДанныеФайла,
					Новый СжатиеДанных(9));
				МенеджерЗаписи.ДатаПоследнегоИзменения = ДатаПоследнегоИзменения;
				МенеджерЗаписи.ДатаНачалаДействия      = ПериодДействияСпискаОтзыва.ДатаНачала;
				МенеджерЗаписи.ДатаОкончанияДействия   = ПериодДействияСпискаОтзыва.ДатаОкончания;

			КонецЕсли;
			
			МенеджерЗаписи.АдресВнутренний = АдресВнутренний;
			МенеджерЗаписи.ДатаПроверки = ТекущаяУниверсальнаяДата();
			МенеджерЗаписи.Записать();
			ЗафиксироватьТранзакцию();

		Исключение
			
			ОтменитьТранзакцию();
			
			Если БлокировкаВыполняется Тогда // Список отзыва находится в процессе обновления.
				Если Не ЗначениеЗаполнено(ДанныеИзКэша) Тогда
					РезультатЗагрузки.СообщениеОбОшибке = НСтр("ru = 'Список отзыва находится в процессе обновления.'");
				КонецЕсли;
			Иначе
				ИнформацияОбОшибке = ИнформацияОбОшибке();
				
				РезультатЗагрузки.СообщениеОбОшибке = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Ошибки при загрузке списка отзыва:
						|%1
						|Подробности см. в Журнале регистрации.'"),
					ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке));
					
				ЗаписьЖурналаРегистрации(
					НСтр("ru = 'Электронная подпись.Обновление списков отзыва'",
					ОбщегоНазначения.КодОсновногоЯзыка()),
					УровеньЖурналаРегистрации.Ошибка, , ,
					ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
				
			КонецЕсли;
			
			Возврат РезультатЗагрузки;
			
		КонецПопытки;
	Иначе
		СкачатьФайлСпискаОтзыва(Адреса, РезультатЗагрузки);
	КонецЕсли;
	
	Возврат РезультатЗагрузки;

КонецФункции


// Для процедуры СкачатьФайлСпискаОтзываНаСервере
Процедура СкачатьФайлСпискаОтзыва(Адреса, РезультатЗагрузки, ДанныеИзКэша = Неопределено, ДатаПоследнегоИзменения = Неопределено)
	
	МодульПолучениеФайловИзИнтернета = ОбщегоНазначения.ОбщийМодуль("ПолучениеФайловИзИнтернета");
	МодульПолучениеФайловИзИнтернетаКлиентСервер = ОбщегоНазначения.ОбщийМодуль("ПолучениеФайловИзИнтернетаКлиентСервер");
	
	Для Каждого ТекущийАдрес Из Адреса Цикл
		
		ПараметрыПолученияФайла = МодульПолучениеФайловИзИнтернетаКлиентСервер.ПараметрыПолученияФайла();
		
		Если ЗначениеЗаполнено(ДанныеИзКэша)
			И ЗначениеЗаполнено(ДанныеИзКэша.ДатаПоследнегоИзменения)
			И ДанныеИзКэша.АдресСпискаОтзыва = ТекущийАдрес Тогда
			
			ДатаПоследнегоИзменения = ДанныеИзКэша.ДатаПоследнегоИзменения;
		КонецЕсли;
		
		Если ЗначениеЗаполнено(ДатаПоследнегоИзменения) Тогда
			ПараметрыПолученияФайла.Заголовки.Вставить("If-Modified-Since", 
					ОбщегоНазначенияКлиентСервер.ДатаHTTP(ДатаПоследнегоИзменения));
		КонецЕсли;
		
		РезультатЗагрузки.АдресФайла = ТекущийАдрес;
		Результат = МодульПолучениеФайловИзИнтернета.СкачатьФайлНаСервере(ТекущийАдрес, ПараметрыПолученияФайла);
		
		Если Результат.КодСостояния = 304 И ЗначениеЗаполнено(ДанныеИзКэша) Тогда // Файл не был обновлен.
			ЗаполнитьРезультатЗагрузкиСпискаОтзываИзДанныхКэша(РезультатЗагрузки, ДанныеИзКэша);
			Возврат;
		КонецЕсли;
			
		Если Результат.Статус Тогда
			ДатаПоследнегоИзменения = ДатаПоследнегоИзмененияФайла(Результат);
			
			ИмяФайла = ИмяФайлаСпискаОтзыва(ТекущийАдрес);
			
			ПутьКФайлу = Результат.Путь;
			
			ВременныйКаталог = Неопределено;
			Если СтрЗаканчиваетсяНа(ИмяФайла, ".zip") Тогда
				ВременныйКаталог = ФайловаяСистема.СоздатьВременныйКаталог(
					Строка(Новый УникальныйИдентификатор));
				ЧтениеZipФайла = Новый ЧтениеZipФайла(ПутьКФайлу);
				
				Для Каждого ЭлементАрхива Из ЧтениеZipФайла.Элементы Цикл
					ИмяФайлаВАрхиве = ЭлементАрхива.Имя;
					ЧтениеZipФайла.Извлечь(ЭлементАрхива, ВременныйКаталог);
					ПутьКФайлу = ВременныйКаталог + ИмяФайлаВАрхиве;
					Прервать;
				КонецЦикла;
				
				ЧтениеZipФайла.Закрыть();
			КонецЕсли;
			
			РезультатЗагрузки.ИмяФайла = ИмяФайла;
			РезультатЗагрузки.ДанныеФайла = Новый ДвоичныеДанные(ПутьКФайлу);
			Если ВременныйКаталог <> Неопределено Тогда
				ФайловаяСистема.УдалитьВременныйКаталог(ВременныйКаталог);
			КонецЕсли;
			ФайловаяСистема.УдалитьВременныйФайл(Результат.Путь);
			
			Прервать;
		Иначе
			ДатаПоследнегоИзменения = Неопределено;
			РезультатЗагрузки.Вставить("СообщениеОбОшибке", Результат.СообщениеОбОшибке);
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ИмяФайлаСпискаОтзыва(АдресСпискаОтзыва)
	
	ПутьНаСервере = ОбщегоНазначенияКлиентСервер.СтруктураURI(АдресСпискаОтзыва).ПутьНаСервере;
	
	ЭлементыПути = СтрРазделить(ПутьНаСервере, "/");
	
	Возврат ОбщегоНазначенияКлиентСервер.ЗаменитьНедопустимыеСимволыВИмениФайла(ЭлементыПути[ЭлементыПути.ВГраница()]);

КонецФункции

// Для процедуры СкачатьФайлСпискаОтзываНаСервере
Функция ДанныеСпискаОтзываИзБазы(АдресВнутренний)
	
	Запрос = Новый Запрос;
	Запрос.Текст =
		"ВЫБРАТЬ
		|	СпискиОтзыва.АдресВнутренний,
		|	СпискиОтзыва.СписокОтзыва,
		|	СпискиОтзыва.ДатаПроверки,
		|	СпискиОтзыва.АдресСпискаОтзыва,
		|	СпискиОтзыва.ДатаПоследнегоИзменения,
		|	СпискиОтзыва.ДатаНачалаДействия,
		|	СпискиОтзыва.ДатаОкончанияДействия
		|ИЗ
		|	РегистрСведений.СпискиОтзываСертификатов КАК СпискиОтзыва
		|ГДЕ
		|	СпискиОтзыва.АдресВнутренний = &АдресВнутренний";
	
	Запрос.УстановитьПараметр("АдресВнутренний", АдресВнутренний);
	
	
	УстановитьПривилегированныйРежим(Истина);
	РезультатЗапроса = Запрос.Выполнить();
	УстановитьПривилегированныйРежим(Ложь);
	
	Результат = Новый Структура("АдресВнутренний, СписокОтзыва, ДатаПроверки, 
		|ДатаПоследнегоИзменения, АдресСпискаОтзыва, ДатаНачалаДействия, ДатаОкончанияДействия");
	
	Если РезультатЗапроса.Пустой() Тогда
		Возврат Результат;
	КонецЕсли;
	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
		ЗаполнитьЗначенияСвойств(Результат, ВыборкаДетальныеЗаписи);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Для процедуры СкачатьФайлСпискаОтзываНаСервере и проверки ПередЗаписью в регистре СпискиОтзываСертификатов.
Функция ПериодДействияСпискаОтзыва(Данные) Экспорт
	
	ДвоичныеДанные = ЭлектроннаяПодписьСлужебныйКлиентСервер.ДвоичныеДанныеИзДанных(
		Данные, "ЭлектроннаяПодписьСлужебный.ПериодДействияСпискаОтзыва");
	
	АнализДанных = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыйАнализДанных(ДвоичныеДанные);
	
	Результат = Новый Структура("ДатаНачала, ДатаОкончания");
	
	// SEQUENCE (CertificateList).
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 16);
			// SEQUENCE (TBSCertList).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 16);
				// INTEGER  (version          Version).
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 2);
				// SEQUENCE (signature            AlgorithmIdentifier).
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 16);
				// SEQUENCE (issuer               Name).
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 16);
				
				Если АнализДанных.ЕстьОшибка Тогда
					Возврат Неопределено;
				КонецЕсли;
				
				// UTC TIME (thisUpdate).
				Результат.ДатаНачала = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПрочитатьДатуИзБуфера(АнализДанных.Буфер, АнализДанных.Смещение);
				// UTC TIME (nextUpdate).
				Результат.ДатаОкончания = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПрочитатьДатуИзБуфера(АнализДанных.Буфер, АнализДанных.Смещение + 15);
	
	Возврат Результат;
	
КонецФункции

// Для процедуры СкачатьФайлСпискаОтзываНаСервере
Процедура ЗаполнитьРезультатЗагрузкиСпискаОтзываИзДанныхКэша(РезультатЗагрузки, ДанныеИзКэша)
	
	ДанныеФайла = ДанныеИзКэша.СписокОтзыва.Получить();
	
	Если Не ЗначениеЗаполнено(ДанныеФайла) Тогда
		
		РезультатЗагрузки.АдресФайла = Неопределено;
		РезультатЗагрузки.ИмяФайла = Неопределено;
		РезультатЗагрузки.ДанныеФайла = Неопределено;
		РезультатЗагрузки.СообщениеОбОшибке = НСтр("ru = 'Список отзыва не загружен.'");
		Возврат;
		
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(ДанныеИзКэша.ДатаОкончанияДействия) 
		Или ДанныеИзКэша.ДатаОкончанияДействия < ТекущаяУниверсальнаяДата() Тогда
		
		РезультатЗагрузки.АдресФайла = Неопределено;
		РезультатЗагрузки.ИмяФайла = Неопределено;
		РезультатЗагрузки.ДанныеФайла = Неопределено;
		РезультатЗагрузки.СообщениеОбОшибке = НСтр("ru = 'Список отзыва просрочен.'");
		Возврат;
		
	КонецЕсли;
	
	РезультатЗагрузки.АдресФайла = ДанныеИзКэша.АдресСпискаОтзыва;
	РезультатЗагрузки.ИмяФайла = ИмяФайлаСпискаОтзыва(ДанныеИзКэша.АдресСпискаОтзыва);
	РезультатЗагрузки.ДанныеФайла = ДанныеФайла;
	
КонецПроцедуры

Функция ЦепочкаСертификатов(Знач Сертификат, ИдентификаторФормы = Неопределено, ОбъектКомпоненты = Неопределено) Экспорт
	
	Сертификат = СертификатBase64Строка(Сертификат);
	Результат = Новый Структура("Сертификаты, Ошибка", Новый Массив, ""); 
	
	Попытка
		Если ОбъектКомпоненты = Неопределено Тогда
			ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
		КонецЕсли;
		
		СертификатыРезультат = ОбъектКомпоненты.ПолучитьЦепочкуСертификатов(Сертификат);
		
		Ошибка = ОбъектКомпоненты.СписокОшибок;
		Если ЗначениеЗаполнено(Ошибка) Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось получить цепочку сертификатов: %1 (%2).'"), Ошибка, ИмяКомпьютера());
		КонецЕсли;
		
		Если СертификатыРезультат = Неопределено Тогда
			ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось получить цепочку сертификатов (%1).'"), ИмяКомпьютера());
		КонецЕсли;
		
		Результат = ЭлектроннаяПодписьСлужебныйКлиентСервер.ЦепочкаСертификатовИзОтветаКомпоненты(
			СертификатыРезультат, ИдентификаторФормы);
	Исключение
		Результат.Ошибка = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		Возврат Результат;
	КонецПопытки;

	Возврат Результат;
	
КонецФункции

Функция СвойстваСертификатаРасширенные(Знач Сертификат, ИдентификаторФормы = Неопределено, ОбъектКомпоненты = Неопределено) Экспорт
	
	Сертификат = СертификатBase64Строка(Сертификат);
	
	Результат = Новый Структура("Ошибка, СвойстваСертификата, СертификатBase64Строка", "");
	Результат.СертификатBase64Строка = Сертификат;
		
	Попытка
		
		СвойстваСертификата = Новый Структура;
		СвойстваСертификата.Вставить("АдресаСписковОтзыва", Новый Массив);
		
		Если ОбъектКомпоненты = Неопределено Тогда
			ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
		КонецЕсли;
	
		СвойстваСертификатаРезультат = ОбъектКомпоненты.ПолучитьСвойстваСертификата(Сертификат);
		
		СвойстваСертификата = ЭлектроннаяПодписьСлужебныйКлиентСервер.СвойстваСертификатаИзОтветаКомпоненты(
			СвойстваСертификатаРезультат);
	
		Результат.СвойстваСертификата = СвойстваСертификата;
		
	Исключение
		
		Результат.Ошибка = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка при получении расширенных свойств сертификата: %1'"),
			ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
		Возврат Результат;
		
	КонецПопытки;
	
	Возврат Результат;
	
КонецФункции

// Сертификат base64 строка.
// 
// Параметры:
//  Сертификат - ДвоичныеДанные
//             - Строка - адрес во временном хранилище
//             - Строка - сертификат в формате Base64Строка
//             - СертификатКриптографии
// 
// Возвращаемое значение:
//  Строка - сертификат base64 строка
//
Функция СертификатBase64Строка(Знач Сертификат)
	
	Если ТипЗнч(Сертификат) = Тип("Строка") И ЭтоАдресВременногоХранилища(Сертификат) Тогда
		Сертификат = ПолучитьИзВременногоХранилища(Сертификат);
	КонецЕсли;

	Если ТипЗнч(Сертификат) = Тип("Строка") Тогда
		Возврат Сертификат;
	КонецЕсли;
	
	Если ТипЗнч(Сертификат) = Тип("СертификатКриптографии") Тогда
		Сертификат = Сертификат.Выгрузить();
	КонецЕсли;
	
	Сертификат = Base64Строка(Сертификат);
	Сертификат = СтрЗаменить(Сертификат, Символы.ВК, "");
	Сертификат = СтрЗаменить(Сертификат, Символы.ПС, "");

	Возврат Сертификат;
	
КонецФункции

Функция ДатаПоследнегоИзмененияФайла(РезультатЗагрузки) Экспорт
	
	Заголовки = Неопределено;
	Если ТипЗнч(РезультатЗагрузки) = Тип("Структура") Тогда
		Заголовки = ОбщегоНазначенияКлиентСервер.СвойствоСтруктуры(РезультатЗагрузки, "Заголовки", Неопределено);
	ИначеЕсли ТипЗнч(РезультатЗагрузки) = Тип("HTTPОтвет") Тогда
		Заголовки = РезультатЗагрузки.Заголовки;
	КонецЕсли;
	
	Если Заголовки = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ДатаПоследнегоИзмененияСтрока = Заголовки["Last-Modified"];
	Если ДатаПоследнегоИзмененияСтрока <> Неопределено Тогда
		Возврат ОбщегоНазначенияКлиентСервер.ДатаRFC1123(ДатаПоследнегоИзмененияСтрока);
	КонецЕсли;
	
	Возврат Неопределено;

КонецФункции

// Локализация

Процедура УстановитьСписокОтзываСертификата(Сертификат, Адреса = Неопределено, АдресВнутренний = Неопределено) Экспорт
	
	ОбъектКомпоненты = ОбъектВнешнейКомпонентыExtraCryptoAPI();
	
	Если ТипЗнч(ОбъектКомпоненты) = Тип("Строка") Тогда
		ВызватьИсключение ОбъектКомпоненты;
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(Адреса) Тогда
		СвойстваСертификатаРасширенные = СвойстваСертификатаРасширенные(Сертификат, ОбъектКомпоненты);
		
		Если ЗначениеЗаполнено(СвойстваСертификатаРасширенные.Ошибка) Тогда
			ВызватьИсключение СвойстваСертификатаРасширенные.Ошибка;
		КонецЕсли;
		
		АдресаСписковОтзыва = СвойстваСертификатаРасширенные.СвойстваСертификата.АдресаСписковОтзыва;
		Если АдресаСписковОтзыва.Количество() = 0 Тогда
			ВызватьИсключение НСтр("ru = 'В сертификате не указаны адреса списков отзыва.'");
		КонецЕсли;
	Иначе
		Если ТипЗнч(Адреса) = Тип("Строка") Тогда
			АдресаСписковОтзыва = СтрРазделить(Адреса, ";");
		КонецЕсли;
	КонецЕсли;

	Результат = СкачатьФайлСпискаОтзываНаСервере(АдресаСписковОтзыва, АдресВнутренний);
	
	Если ЗначениеЗаполнено(Результат.СообщениеОбОшибке) Тогда
		ВызватьИсключение Результат.СообщениеОбОшибке;
	КонецЕсли;
	
	РезультатУстановки = Ложь;
	ОписаниеОшибки = "";
	
	ДанныеФайла = Результат.ДанныеФайла;
	ИмяВременногоФайла = ПолучитьИмяВременногоФайла(".crl");
	ДанныеФайла.Записать(ИмяВременногоФайла);
	Попытка
		ОбъектКомпоненты.ИмпортироватьСписокОтзываСертификатов(ИмяВременногоФайла, "CA");
		РезультатУстановки = Истина;
	Исключение
		ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
		РезультатУстановки = Ложь;
	КонецПопытки;
	
	ФайловаяСистема.УдалитьВременныйФайл(ИмяВременногоФайла);
	
	Если Не РезультатУстановки Тогда
		ВызватьИсключение ОписаниеОшибки;
	КонецЕсли;
	
КонецПроцедуры

// Конец Локализация

#КонецОбласти

#Область ОбновлениеИнформационнойБазы

// Заменяет роль ДобавлениеИзменениеЭлектронныхПодписейИШифрование во всех профилях, в которые она входит
// на роли ДобавлениеИзменениеЭлектронныхПодписей, ДобавлениеИзменениеСертификатовКлючейЭлектроннойПодписиИШифрования
// и ШифрованиеИРасшифровкаДанных.
//
Процедура ЗаменитьРольДобавлениеИзменениеЭлектронныхПодписейИШифрование() Экспорт
	
	Если Не ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		Возврат;
	КонецЕсли;
	
	МодульУправлениеДоступом = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
	
	НовыеРоли = Новый Массив;
	НовыеРоли.Добавить("ДобавлениеИзменениеЭлектронныхПодписей");
	НовыеРоли.Добавить("ШифрованиеИРасшифровкаДанных");
	НовыеРоли.Добавить("ДобавлениеИзменениеСертификатовКлючейЭлектроннойПодписиИШифрования");
	ЗаменяемыеРоли = Новый Соответствие;
	ЗаменяемыеРоли.Вставить("? ДобавлениеИзменениеЭлектронныхПодписейИШифрование", НовыеРоли);
	
	МодульУправлениеДоступом.ЗаменитьРолиВПрофилях(ЗаменяемыеРоли);
	
КонецПроцедуры

#КонецОбласти

#Область СодержимоеСертификата

// Расширенные данные для печати сертификата.
// 
// Параметры:
//  Данные - ДвоичныеДанные - данные сертификата
// 
// Возвращаемое значение:
//  Структура - расширенные данные для печати сертификата:
//   * ТипИдентификации - Число
//   * СКЗИ - Строка
//   * Заключение - Строка
//   * СКЗИ_УЦ - Строка
//   * ЗаключениеУЦ - Строка
//   * Подпись - ДвоичныеДанные
//
Функция РасширенныеДанныеДляПечатиСертификата(Данные) Экспорт
	
	Структура = Новый Структура("ТипИдентификации, СКЗИ, Заключение, СКЗИ_УЦ, ЗаключениеУЦ, Подпись");
	
	АнализДанных = ЭлектроннаяПодписьСлужебныйКлиентСервер.НовыйАнализДанных(Данные);
	// SEQUENCE (Certificate).
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 16);
		// SEQUENCE (tbsCertificate).
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 16);
			// [0] EXPLICIT (version).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 2, 0);
			// INTEGER  (serialNumber         CertificateSerialNumber).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 2);
			// SEQUENCE (signature            AlgorithmIdentifier).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 16);
			// SEQUENCE (issuer               Name).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 16);
			// SEQUENCE (validity             Validity).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 16);
			// SEQUENCE (subject              Name).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 16);
			// SEQUENCE (subjectPublicKeyInfo SubjectPublicKeyInfo).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 16);
			// [1] IMPLICIT UniqueIdentifier OPTIONAL (issuerUniqueID).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 2, 1, Ложь);
			// [2] IMPLICIT UniqueIdentifier OPTIONAL (subjectUniqueID).
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 2, 2, Ложь);
			// [3] EXPLICIT SEQUENCE SIZE (1..MAX) OF Extension (extensions). 
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 2, 3);
				// SEQUENCE OF
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 16);
				СмещениеСледующего = АнализДанных.Родители[0].СмещениеСледующего;
				Пока АнализДанных.Смещение < СмещениеСледующего Цикл
					// SEQUENCE (extension).
					ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 16);
					Если АнализДанных.ЕстьОшибка Тогда
						Прервать;
					КонецЕсли; 
						// OBJECT IDENTIFIER
						ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 6);
							РазмерДанных = АнализДанных.Родители[0].РазмерДанных;
							Буфер = АнализДанных.Буфер.Прочитать(АнализДанных.Смещение, РазмерДанных); // БуферДвоичныхДанных
							СтрокаБуфера = ПолучитьHexСтрокуИзБуфераДвоичныхДанных(Буфер); // Идентификатор
						ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьРодительскийБлок(АнализДанных); // OBJECT IDENTIFIER

						Если СтрокаБуфера = "2A85036470" Тогда // 1.2.643.100.112
							ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 4); // OCTET STRING
								// IssuerSignTool ::= SEQUENCE {
								//  signTool     UTF8String SIZE(1..200),
								//  cATool       UTF8String SIZE(1..200),
								//  signToolCert UTF8String SIZE(1..100),
								//  cAToolCert   UTF8String SIZE(1..100) }.
								// SEQUENCE (IssuerSignTool).
								ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 16); // SEQUENCE
									Структура.СКЗИ = СтрокаUTF8(АнализДанных);
									Структура.СКЗИ_УЦ = СтрокаUTF8(АнализДанных);
									Структура.Заключение = СтрокаUTF8(АнализДанных);
									Структура.ЗаключениеУЦ = СтрокаUTF8(АнализДанных);
								АнализДанных.Родители.Удалить(0); // SEQUENCE
							АнализДанных.Родители.Удалить(0); // OCTET STRING
						ИначеЕсли СтрокаБуфера = "2A85036472" Тогда // 1.2.643.100.114
							ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 4); // OCTET STRING
								ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 2); // INTEGER
									Структура.ТипИдентификации = ЭлектроннаяПодписьСлужебныйКлиентСервер.ПрочитатьПотоковоеЦелое(АнализДанных);
								АнализДанных.Родители.Удалить(0); // INTEGER
							АнализДанных.Родители.Удалить(0); // OCTET STRING
						КонецЕсли;
							
					ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьРодительскийБлок(АнализДанных); // SEQUENCE
				КонецЦикла; 
				ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьРодительскийБлок(АнализДанных); // SEQUENCE OF
			ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьРодительскийБлок(АнализДанных); // EXPLICIT SEQUENCE
		ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьРодительскийБлок(АнализДанных); // SEQUENCE (tbsCertificate)
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьБлок(АнализДанных, 0, 16); // signatureAlgorithm
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 3); // signatureValue
	Если НЕ АнализДанных.ЕстьОшибка Тогда
		РазмерДанных = АнализДанных.Родители[0].РазмерДанных;
		Буфер = АнализДанных.Буфер.Прочитать(АнализДанных.Смещение, РазмерДанных); // БуферДвоичныхДанных
		Структура.Подпись = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(Буфер);
	Иначе 
		ВызватьИсключение НСтр("ru = 'Непредвиденная ситуация при чтении расширенных данных сертификата.'");
	КонецЕсли;

	Возврат Структура;
	
КонецФункции

Функция СтрокаUTF8(АнализДанных)
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьНачалоБлока(АнализДанных, 0, 12); // UTF8String
	
	РазмерДанных = АнализДанных.Родители[0].РазмерДанных;
	Буфер = АнализДанных.Буфер.Прочитать(АнализДанных.Смещение, РазмерДанных); // БуферДвоичныхДанных
	Строка = ПолучитьСтрокуИзБуфераДвоичныхДанных(Буфер, "UTF-8");
	
	ЭлектроннаяПодписьСлужебныйКлиентСервер.ПропуститьРодительскийБлок(АнализДанных); // UTF8String
	
	Возврат Строка;
	
КонецФункции

#КонецОбласти

#КонецОбласти